diff --git a/README.md b/README.md
index 50fc6c0a..d7a50670 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,9 @@
-
+
+
+
@@ -41,7 +43,7 @@ There are lots of other tools that sync scripts into Roblox or provide other too
Here are a few, if you're looking for alternatives or supplements to Rojo:
* [rbxmk by Anaminus](https://github.com/anaminus/rbxmk)
-* [RbxRefresh by Osyris](https://github.com/osyrisrblx/RbxRefresh)
+* [Rofresh](https://github.com/osyrisrblx/rofresh) and [RbxRefresh](https://github.com/osyrisrblx/RbxRefresh) by [Osyris](https://github.com/osyrisrblx)
* [Studio Bridge by Vocksel](https://github.com/vocksel/studio-bridge)
* [RbxSync by evaera](https://github.com/evaera/RbxSync)
* [CodeSync](https://github.com/MemoryPenguin/CodeSync) and [rbx-exteditor](https://github.com/MemoryPenguin/rbx-exteditor) by [MemoryPenguin](https://github.com/MemoryPenguin)
diff --git a/integration/.gitignore b/integration/.gitignore
new file mode 100644
index 00000000..a79a8002
--- /dev/null
+++ b/integration/.gitignore
@@ -0,0 +1,2 @@
+/target/
+**/*.rs.bk
\ No newline at end of file
diff --git a/integration/Cargo.lock b/integration/Cargo.lock
new file mode 100644
index 00000000..02b1e530
--- /dev/null
+++ b/integration/Cargo.lock
@@ -0,0 +1,4 @@
+[[package]]
+name = "integration"
+version = "0.1.0"
+
diff --git a/integration/Cargo.toml b/integration/Cargo.toml
new file mode 100644
index 00000000..769e48aa
--- /dev/null
+++ b/integration/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "integration"
+version = "0.1.0"
+authors = ["Lucien Greathouse "]
+
+[dependencies]
diff --git a/integration/README.md b/integration/README.md
new file mode 100644
index 00000000..e211270b
--- /dev/null
+++ b/integration/README.md
@@ -0,0 +1,2 @@
+# Rojo Integration Runner
+This is a WIP test runner designed for Rojo. It will eventually start up the Rojo server and plugin and test functionality end-to-end.
\ No newline at end of file
diff --git a/integration/src/main.rs b/integration/src/main.rs
new file mode 100644
index 00000000..4e4883b1
--- /dev/null
+++ b/integration/src/main.rs
@@ -0,0 +1,32 @@
+use std::{
+ path::Path,
+ process::Command,
+ thread,
+ time::Duration,
+};
+
+fn main() {
+ let plugin_path = Path::new("../plugin");
+ let server_path = Path::new("../server");
+ let tests_path = Path::new("../tests");
+
+ let server = Command::new("cargo")
+ .args(&["run", "--", "serve", "../test-projects/empty"])
+ .current_dir(server_path)
+ .spawn();
+
+ thread::sleep(Duration::from_millis(1000));
+
+ // TODO: Wait for server to start responding on the right port
+
+ let test_client = Command::new("lua")
+ .args(&["runTest.lua", "tests/empty.lua"])
+ .current_dir(plugin_path)
+ .spawn();
+
+ thread::sleep(Duration::from_millis(300));
+
+ // TODO: Collect output from the client for success/failure?
+
+ println!("Dying!");
+}
diff --git a/plugin/README.md b/plugin/README.md
new file mode 100644
index 00000000..f3f68394
--- /dev/null
+++ b/plugin/README.md
@@ -0,0 +1,5 @@
+# Rojo Plugin
+
+This is the source to the Rojo Roblox Studio plugin.
+
+Documentation is WIP.
\ No newline at end of file
diff --git a/plugin/loadEnvironment.lua b/plugin/loadEnvironment.lua
new file mode 100644
index 00000000..e7065daa
--- /dev/null
+++ b/plugin/loadEnvironment.lua
@@ -0,0 +1,37 @@
+--[[
+ Loads the Rojo plugin and all of its dependencies.
+]]
+
+local function loadEnvironment()
+ -- If you add any dependencies, add them to this table so they'll be loaded!
+ local LOAD_MODULES = {
+ {"src", "Rojo"},
+ {"modules/promise/lib", "Promise"},
+ {"modules/testez/lib", "TestEZ"},
+ }
+
+ -- This makes sure we can load Lemur and other libraries that depend on init.lua
+ package.path = package.path .. ";?/init.lua"
+
+ -- If this fails, make sure you've run `lua bin/install-dependencies.lua` first!
+ local lemur = require("modules.lemur")
+
+ -- Create a virtual Roblox tree
+ local habitat = lemur.Habitat.new()
+
+ -- We'll put all of our library code and dependencies here
+ local modules = lemur.Instance.new("Folder")
+ modules.Name = "Modules"
+ modules.Parent = habitat.game:GetService("ReplicatedStorage")
+
+ -- Load all of the modules specified above
+ for _, module in ipairs(LOAD_MODULES) do
+ local container = habitat:loadFromFs(module[1])
+ container.Name = module[2]
+ container.Parent = modules
+ end
+
+ return habitat, modules
+end
+
+return loadEnvironment
\ No newline at end of file
diff --git a/plugin/modules/lemur b/plugin/modules/lemur
index 86b33cdf..96d4166a 160000
--- a/plugin/modules/lemur
+++ b/plugin/modules/lemur
@@ -1 +1 @@
-Subproject commit 86b33cdfb46fd1e736f8ee1d8861d1b58ffa987f
+Subproject commit 96d4166a2d9e146e6955eeacccc0c79a86a177f5
diff --git a/plugin/rojo.json b/plugin/rojo.json
index 17f5548f..2276882c 100644
--- a/plugin/rojo.json
+++ b/plugin/rojo.json
@@ -4,31 +4,31 @@
"partitions": {
"plugin": {
"path": "src",
- "target": "ReplicatedStorage.Rojo.modules.Plugin"
+ "target": "ReplicatedStorage.Rojo.Modules.Plugin"
},
"modules/roact": {
"path": "modules/roact/lib",
- "target": "ReplicatedStorage.Rojo.modules.Roact"
+ "target": "ReplicatedStorage.Rojo.Modules.Roact"
},
"modules/rodux": {
"path": "modules/rodux/lib",
- "target": "ReplicatedStorage.Rojo.modules.Rodux"
+ "target": "ReplicatedStorage.Rojo.Modules.Rodux"
},
"modules/roact-rodux": {
"path": "modules/roact-rodux/lib",
- "target": "ReplicatedStorage.Rojo.modules.RoactRodux"
+ "target": "ReplicatedStorage.Rojo.Modules.RoactRodux"
+ },
+ "modules/promise": {
+ "path": "modules/promise/lib",
+ "target": "ReplicatedStorage.Rojo.Modules.Promise"
},
"modules/testez": {
"path": "modules/testez/lib",
"target": "ReplicatedStorage.TestEZ"
},
- "modules/promise": {
- "path": "modules/promise/lib",
- "target": "ReplicatedStorage.Rojo.modules.Promise"
- },
"tests": {
- "path": "tests",
- "target": "TestService"
+ "path": "testBootstrap.server.lua",
+ "target": "TestService.testBootstrap"
}
}
}
\ No newline at end of file
diff --git a/plugin/runTest.lua b/plugin/runTest.lua
new file mode 100644
index 00000000..a3a682d0
--- /dev/null
+++ b/plugin/runTest.lua
@@ -0,0 +1,15 @@
+local loadEnvironment = require("loadEnvironment")
+
+local testPath = assert((...), "Please specify a path to a test file.")
+
+local habitat = loadEnvironment()
+
+local testModule = habitat:loadFromFs(testPath)
+
+if testModule == nil then
+ error("Couldn't find test file at " .. testPath)
+end
+
+print("Starting test module.")
+
+habitat:require(testModule)
\ No newline at end of file
diff --git a/plugin/spec.lua b/plugin/spec.lua
index 102093f1..25e23181 100644
--- a/plugin/spec.lua
+++ b/plugin/spec.lua
@@ -2,37 +2,14 @@
Loads our library and all of its dependencies, then runs tests using TestEZ.
]]
--- If you add any dependencies, add them to this table so they'll be loaded!
-local LOAD_MODULES = {
- {"src", "plugin"},
- {"modules/promise/lib", "Promise"},
- {"modules/testez/lib", "TestEZ"},
-}
+local loadEnvironment = require("loadEnvironment")
--- This makes sure we can load Lemur and other libraries that depend on init.lua
-package.path = package.path .. ";?/init.lua"
-
--- If this fails, make sure you've run `lua bin/install-dependencies.lua` first!
-local lemur = require("modules.lemur")
-
--- Create a virtual Roblox tree
-local habitat = lemur.Habitat.new()
-
--- We'll put all of our library code and dependencies here
-local Root = lemur.Instance.new("Folder")
-Root.Name = "Root"
-
--- Load all of the modules specified above
-for _, module in ipairs(LOAD_MODULES) do
- local container = habitat:loadFromFs(module[1])
- container.Name = module[2]
- container.Parent = Root
-end
+local habitat, modules = loadEnvironment()
-- Load TestEZ and run our tests
-local TestEZ = habitat:require(Root.TestEZ)
+local TestEZ = habitat:require(modules.TestEZ)
-local results = TestEZ.TestBootstrap:run(Root.plugin, TestEZ.Reporters.TextReporter)
+local results = TestEZ.TestBootstrap:run(modules.Rojo, TestEZ.Reporters.TextReporter)
-- Did something go wrong?
if results.failureCount > 0 then
diff --git a/plugin/src/ApiContext.lua b/plugin/src/ApiContext.lua
index d8d301e1..19dd19eb 100644
--- a/plugin/src/ApiContext.lua
+++ b/plugin/src/ApiContext.lua
@@ -19,14 +19,15 @@ setmetatable(ApiContext.Error, {
end
})
-function ApiContext.new(url, onMessage)
- assert(type(url) == "string")
+function ApiContext.new(baseUrl, onMessage)
+ assert(type(baseUrl) == "string")
assert(type(onMessage) == "function")
local context = {
- url = url,
+ baseUrl = baseUrl,
onMessage = onMessage,
serverId = nil,
+ rootInstanceId = nil,
connected = false,
messageCursor = -1,
partitionRoutes = nil,
@@ -38,7 +39,9 @@ function ApiContext.new(url, onMessage)
end
function ApiContext:connect()
- return Http.get(self.url .. "/api/rojo")
+ local url = ("%s/api/rojo"):format(self.baseUrl)
+
+ return Http.get(url)
:andThen(function(response)
local body = response:json()
@@ -61,15 +64,18 @@ function ApiContext:connect()
self.serverId = body.serverId
self.connected = true
self.partitionRoutes = body.partitions
+ self.rootInstanceId = body.rootInstanceId
end)
end
-function ApiContext:readAll()
+function ApiContext:read(ids)
if not self.connected then
return Promise.reject()
end
- return Http.get(self.url .. "/api/read_all")
+ local url = ("%s/api/read/%s"):format(self.baseUrl, table.concat(ids, ","))
+
+ return Http.get(url)
:andThen(function(response)
local body = response:json()
@@ -92,7 +98,9 @@ function ApiContext:retrieveMessages()
return Promise.reject()
end
- return Http.get(self.url .. "/api/subscribe/" .. self.messageCursor)
+ local url = ("%s/api/subscribe/%s"):format(self.baseUrl, self.messageCursor)
+
+ return Http.get(url)
:andThen(function(response)
local body = response:json()
diff --git a/plugin/src/Http.lua b/plugin/src/Http.lua
index d6dd9cdb..57cedc15 100644
--- a/plugin/src/Http.lua
+++ b/plugin/src/Http.lua
@@ -1,6 +1,6 @@
local HttpService = game:GetService("HttpService")
-local HTTP_DEBUG = false
+local HTTP_DEBUG = true
local Promise = require(script.Parent.Parent.Promise)
diff --git a/plugin/src/Session.lua b/plugin/src/Session.lua
index 47d8d5d0..4eb1d012 100644
--- a/plugin/src/Session.lua
+++ b/plugin/src/Session.lua
@@ -11,57 +11,7 @@ function Session.new()
setmetatable(self, Session)
- local function createFoldersUntil(location, route)
- for i = 1, #route - 1 do
- local piece = route[i]
-
- local child = location:FindFirstChild(piece)
-
- if child == nil then
- child = Instance.new("Folder")
- child.Name = piece
- child.Parent = location
- end
-
- location = child
- end
-
- return location
- end
-
- local function reify(instancesById, id)
- local object = instancesById[tostring(id)]
- local instance = Instance.new(object.className)
- instance.Name = object.name
-
- for key, property in pairs(object.properties) do
- instance[key] = property.value
- end
-
- for _, childId in ipairs(object.children) do
- reify(instancesById, childId).Parent = instance
- end
-
- return instance
- end
-
local api
- local function readAll()
- print("Reading all...")
-
- return api:readAll()
- :andThen(function(response)
- for partitionName, partitionRoute in pairs(api.partitionRoutes) do
- local parent = createFoldersUntil(game, partitionRoute)
-
- local rootInstanceId = response.partitionInstances[partitionName]
-
- print("Root for", partitionName, "is", rootInstanceId)
-
- reify(response.instances, rootInstanceId).Parent = parent
- end
- end)
- end
api = ApiContext.new(REMOTE_URL, function(message)
if message.type == "InstanceChanged" then
@@ -73,7 +23,9 @@ function Session.new()
end)
api:connect()
- :andThen(readAll)
+ :andThen(function()
+ return api:read({api.rootInstanceId})
+ end)
:andThen(function()
return api:retrieveMessages()
end)
diff --git a/plugin/testBootstrap.server.lua b/plugin/testBootstrap.server.lua
new file mode 100644
index 00000000..ae53be9f
--- /dev/null
+++ b/plugin/testBootstrap.server.lua
@@ -0,0 +1,2 @@
+local TestEZ = require(game.ReplicatedStorage.TestEZ)
+TestEZ.TestBootstrap:run(game.ReplicatedStorage.Rojo.plugin)
\ No newline at end of file
diff --git a/plugin/tests/empty.lua b/plugin/tests/empty.lua
new file mode 100644
index 00000000..bfda7fad
--- /dev/null
+++ b/plugin/tests/empty.lua
@@ -0,0 +1,5 @@
+local ReplicatedStorage = game:GetService("ReplicatedStorage")
+
+local Session = require(ReplicatedStorage.Modules.Rojo.Session)
+
+Session.new()
\ No newline at end of file
diff --git a/plugin/tests/runTests.server.lua b/plugin/tests/runTests.server.lua
deleted file mode 100644
index be1a94d5..00000000
--- a/plugin/tests/runTests.server.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-local TestEZ = require(game.ReplicatedStorage.TestEZ)
-TestEZ.TestBootstrap:run(game.ReplicatedStorage.Rojo.plugin)
diff --git a/server/Cargo.lock b/server/Cargo.lock
index bf03e25e..3e0dfd05 100644
--- a/server/Cargo.lock
+++ b/server/Cargo.lock
@@ -1,14 +1,14 @@
[[package]]
name = "adler32"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "aho-corasick"
-version = "0.6.4"
+version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -16,7 +16,7 @@ name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -26,12 +26,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "atty"
-version = "0.2.10"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -39,7 +39,7 @@ name = "base64"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -55,7 +55,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
-version = "1.0.3"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -64,7 +64,7 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -73,7 +73,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"brotli-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -92,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
-version = "1.2.2"
+version = "1.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -102,7 +102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
-version = "0.1.3"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -111,17 +111,17 @@ version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
- "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "chrono"
-version = "0.4.2"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -131,16 +131,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
-version = "2.31.2"
+version = "2.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cloudabi"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -156,16 +164,11 @@ name = "deflate"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"gzip-header 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "dtoa"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "encoding"
version = "0.2.33"
@@ -236,9 +239,9 @@ name = "filetime"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -248,7 +251,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"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)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -256,7 +259,7 @@ name = "fsevent-sys"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -264,7 +267,7 @@ name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -289,17 +292,17 @@ dependencies = [
[[package]]
name = "httparse"
-version = "1.2.4"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "idna"
-version = "0.1.4"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-normalization 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -307,12 +310,12 @@ name = "inotify"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -326,12 +329,15 @@ dependencies = [
[[package]]
name = "lazy_static"
-version = "1.0.0"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "libc"
-version = "0.2.40"
+version = "0.2.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -339,20 +345,20 @@ name = "log"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
-version = "0.4.1"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "matches"
-version = "0.1.6"
+version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -360,15 +366,15 @@ name = "memchr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
-version = "2.0.1"
+version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -381,7 +387,7 @@ dependencies = [
[[package]]
name = "mime_guess"
-version = "1.8.4"
+version = "1.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -396,13 +402,13 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (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)",
- "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.33 (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)",
- "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -412,7 +418,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.33 (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)",
]
@@ -423,10 +429,10 @@ version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"buf_redux 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "mime_guess 1.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime_guess 1.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -435,12 +441,12 @@ dependencies = [
[[package]]
name = "net2"
-version = "0.2.32"
+version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -449,12 +455,12 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "notify"
-version = "4.0.3"
+version = "4.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -463,9 +469,9 @@ dependencies = [
"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)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -474,26 +480,26 @@ name = "num"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
-version = "0.1.36"
+version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
-version = "0.1.35"
+version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -501,12 +507,12 @@ name = "num-traits"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
-version = "0.2.2"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -514,7 +520,7 @@ name = "num_cpus"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -545,7 +551,7 @@ version = "0.7.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -553,13 +559,13 @@ name = "phf_shared"
version = "0.7.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
-version = "0.3.8"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -567,10 +573,10 @@ dependencies = [
[[package]]
name = "quote"
-version = "0.5.2"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -579,23 +585,40 @@ version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
-version = "0.4.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rand"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cloudabi 0.0.3 (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.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "redox_syscall"
-version = "0.1.37"
+version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -603,24 +626,24 @@ name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
-version = "1.0.0"
+version = "1.0.4"
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.6.0 (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)",
+ "aho-corasick 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
-version = "0.6.0"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -631,24 +654,24 @@ name = "remove_dir_all"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rojo"
version = "0.5.0"
dependencies = [
- "clap 2.31.2 (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)",
- "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "notify 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rouille 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -658,21 +681,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"brotli2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"multipart 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.26 (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)",
"threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny_http 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -680,6 +703,11 @@ name = "rustc-serialize"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "ryu"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "safemem"
version = "0.2.0"
@@ -687,35 +715,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "same-file"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde"
-version = "1.0.51"
+version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
-version = "1.0.51"
+version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
-version = "1.0.17"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -725,7 +753,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "siphasher"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -740,11 +768,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
-version = "0.13.7"
+version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -753,20 +781,20 @@ name = "tempdir"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tempfile"
-version = "3.0.2"
+version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -783,26 +811,25 @@ name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
-version = "0.9.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
-version = "0.3.5"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -815,12 +842,12 @@ dependencies = [
[[package]]
name = "time"
-version = "0.1.39"
+version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -841,7 +868,7 @@ name = "twoway"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -854,7 +881,7 @@ name = "unicase"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -862,17 +889,17 @@ name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-normalization"
-version = "0.1.6"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
-version = "0.1.4"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -880,37 +907,29 @@ name = "unicode-xid"
version = "0.1.0"
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]]
name = "url"
version = "0.2.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "url"
-version = "1.7.0"
+version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -924,26 +943,22 @@ dependencies = [
[[package]]
name = "vec_map"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "void"
-version = "1.0.2"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "walkdir"
-version = "2.1.4"
+version = "2.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -953,7 +968,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -970,6 +985,14 @@ name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "winapi-util"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
@@ -985,29 +1008,29 @@ dependencies = [
]
[metadata]
-"checksum adler32 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6cbd0b9af8587c72beadc9f72d35b9fbb070982c9e6203e46e93f10df25f8f45"
-"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
+"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
+"checksum aho-corasick 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "7ee94e9463ccb9d681e7b708082687b2c56d2bd420ca8a3d3157d27d59508ec0"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50"
-"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1"
+"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum base64 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5032d51da2741729bfdaeb2664d9b8c6d9fd1e2b90715c660b6def36628499c2"
"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 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
+"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum brotli-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cb50f54b2e0c671b7ef1637a76237ebacbb293be179440d5d65ca288e42116bb"
"checksum brotli2 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea9d0bbab1235017a09226b079ed733bca4bf9ecb6b6102bd01aac79ea082dca"
"checksum buf_redux 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b9279646319ff816b05fb5897883ece50d7d854d12b59992683d4f8a71b0f949"
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
-"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
+"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781"
"checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27"
-"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18"
+"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
"checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00"
-"checksum chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cce36c92cb605414e9b824f866f5babe0a0368e39ea07393b9b63cf3844c0e6"
+"checksum chrono 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e48d85528df61dc964aa43c5f6ca681a19cfa74939b2348d204bd08a981f2fb0"
"checksum chunked_transfer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "498d20a7aaf62625b9bf26e637cf7736417cde1d0c99f1d04d1170229a85cf87"
-"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
+"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
+"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
"checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31"
-"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
"checksum encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
"checksum encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
@@ -1023,86 +1046,88 @@ dependencies = [
"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 gzip-header 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0a9fcfe1c9ee125342355b2467bc29b9dfcb2124fcae27edb9cee6f4cc5ecd40"
-"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37"
-"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
+"checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540"
+"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887fcc180136e77a85e6a6128579a719027b1bab9b1c38ea4444244fe262c20c"
-"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
+"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
-"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b"
+"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
+"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
"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 log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2"
+"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
-"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
+"checksum memchr 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a3b4142ab8738a78c51896f704f83c11df047ff1bda9a92a661aa6361552d93d"
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
-"checksum mime_guess 1.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b7e2b09d08313f84e0fb82d13a4d859109a17543fe9af3b6d941dc1431f7de79"
+"checksum mime_guess 1.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2d4c0961143b8efdcfa29c3ae63281601b446a4a668165454b6c90f8024954c5"
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
"checksum miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3e690c5df6b2f60acd45d56378981e827ff8295562fc8d34f573deb267a59cd1"
"checksum multipart 0.13.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92f54eb45230c3aa20864ccf0c277eeaeadcf5e437e91731db498dbf7fbe0ec6"
-"checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0"
+"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
-"checksum notify 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5c3812da3098f210a0bb440f9c008471a031aa4c1de07a264fdd75456c95a4eb"
+"checksum notify 4.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d023ef40ca7680784b07be3f49913e1ea176da1b63949f2eb2fed96438bd7f42"
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
-"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe"
-"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593"
+"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
+"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
-"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364"
+"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7d37a244c75a9748e049225155f56dbcb98fe71b192fd25fd23cb914b5ad62f2"
"checksum phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4048fe7dd7a06b8127ecd6d3803149126e9b33c7558879846da3a63f734f2b"
"checksum phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "05a079dd052e7b674d21cb31cbb6c05efd56a2cd2827db7692e2f1a507ebd998"
"checksum phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c2261d544c2bb6aa3b10022b0be371b9c7c64f762ef28c6f5d4f1ef6d97b5930"
-"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7"
-"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8"
+"checksum proc-macro2 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ee5697238f0d893c7f0ecc59c0999f18d2af85e424de441178bcacc9f9e6cf67"
+"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
-"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
-"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
+"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
+"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
+"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2"
+"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
-"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3"
-"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b"
+"checksum regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "67d0301b0c6804eca7e3c275119d0b01ff3b7ab9258a65709e608a66312a1025"
+"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rouille 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc1f8407af80b0630983b2c1f1860dda1960fdec8d3ee75ba8db14937756d3a0"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
+"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
-"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
-"checksum serde 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "21924cc18e5281f232a17c040355fac97732b42cf019c24996a1642bcb169cdb"
-"checksum serde_derive 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "9c624a90bec6fe9bc60d275d7af71c72c26b24cd6c6776d8e344dc4044caa3e2"
-"checksum serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f3ad6d546e765177cf3dded3c2e424a8040f870083a0e64064746b958ece9cb1"
+"checksum same-file 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f7794e2fda7f594866840e95f5c5962e886e228e68b6505885811a94dd728c"
+"checksum serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "22d340507cea0b7e6632900a176101fea959c7065d93ba555072da90aaaafc87"
+"checksum serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)" = "234fc8b737737b148ccd625175fc6390f5e4dacfdaa543cb93a3430d984a9119"
+"checksum serde_json 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "44dd2cfde475037451fa99b7e5df77aa3cfd1536575fa8e7a538ab36dcde49ae"
"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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
-"checksum syn 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "61b8f1b737f929c6516ba46a3133fd6d5215ad8a62f66760f851f7048aebedfb"
+"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
-"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b"
+"checksum tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b103c6d08d323b92ff42c8ce62abcd83ca8efa7fd5bf7927efefec75f58c76"
"checksum term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f2077e54d38055cf1ca0fd7933a2e00cd3ec8f6fed352b2a377f06dcdaaf3281"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
-"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
-"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
+"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
+"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
-"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
+"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
"checksum tiny_http 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2f4d55c9a213880d1f0c89ded183f209c6e45b912ca6c7df6f93c163773572e1"
"checksum twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
-"checksum unicode-normalization 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90d662d111b0dbb08a180f2761026cba648c258023c355954a7c00e00e354636"
-"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
+"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
+"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
-"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 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7"
-"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
+"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
+"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
"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 version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
-"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
+"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
+"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
+"checksum walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "af464bc7be7b785c7ac72e266a6b67c4c9070155606f51655a650a6686204e35"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
-"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
+"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
diff --git a/server/README.md b/server/README.md
new file mode 100644
index 00000000..b3801934
--- /dev/null
+++ b/server/README.md
@@ -0,0 +1,4 @@
+# Rojo Server
+This is the source to the Rojo server.
+
+Documentation is WIP.
\ No newline at end of file
diff --git a/server/src/bin.rs b/server/src/bin.rs
index bf20429e..86232c92 100644
--- a/server/src/bin.rs
+++ b/server/src/bin.rs
@@ -42,20 +42,7 @@ fn main() {
None => std::env::current_dir().unwrap(),
};
- let port = {
- match sub_matches.value_of("port") {
- Some(source) => match source.parse::() {
- Ok(value) => Some(value),
- Err(_) => {
- eprintln!("Invalid port '{}'", source);
- process::exit(1);
- },
- },
- None => None,
- }
- };
-
- librojo::commands::serve(&project_path, port);
+ librojo::commands::serve(&project_path);
},
_ => {
eprintln!("Please specify a subcommand!");
@@ -63,4 +50,4 @@ fn main() {
process::exit(1);
},
}
-}
+}
\ No newline at end of file
diff --git a/server/src/commands/init.rs b/server/src/commands/init.rs
index 96cbbcb3..9050e072 100644
--- a/server/src/commands/init.rs
+++ b/server/src/commands/init.rs
@@ -13,4 +13,4 @@ pub fn init(project_path: &PathBuf) {
process::exit(1);
},
}
-}
+}
\ No newline at end of file
diff --git a/server/src/commands/mod.rs b/server/src/commands/mod.rs
index 58023fa3..db228aa1 100644
--- a/server/src/commands/mod.rs
+++ b/server/src/commands/mod.rs
@@ -2,4 +2,4 @@ mod serve;
mod init;
pub use self::serve::*;
-pub use self::init::*;
+pub use self::init::*;
\ No newline at end of file
diff --git a/server/src/commands/serve.rs b/server/src/commands/serve.rs
index 243ee335..7233c872 100644
--- a/server/src/commands/serve.rs
+++ b/server/src/commands/serve.rs
@@ -1,40 +1,39 @@
-use std::path::PathBuf;
-use std::process;
-use std::fs;
+use std::{
+ path::Path,
+ process,
+ sync::Arc,
+};
-use rand;
+use ::{
+ project::Project,
+ web::Server,
+ session::Session,
+ roblox_studio,
+};
-use project::Project;
-use web::{self, WebConfig};
-use session::Session;
-use roblox_studio;
-
-pub fn serve(project_dir: &PathBuf, override_port: Option) {
- let server_id = rand::random::();
-
- let project = match Project::load(project_dir) {
- Ok(v) => {
- println!("Using project from {}", fs::canonicalize(project_dir).unwrap().display());
- v
- },
- Err(err) => {
- eprintln!("{}", err);
+pub fn serve(fuzzy_project_location: &Path) {
+ let project = match Project::load_fuzzy(fuzzy_project_location) {
+ Ok(project) => project,
+ Err(error) => {
+ eprintln!("Fatal: {}", error);
process::exit(1);
},
};
- let port = override_port.unwrap_or(project.serve_port);
-
+ println!("Found project at {}", project.file_location.display());
println!("Using project {:#?}", project);
roblox_studio::install_bundled_plugin().unwrap();
- let mut session = Session::new(project.clone());
- session.start();
+ let session = Arc::new({
+ let mut session = Session::new(project);
+ session.start().unwrap();
+ session
+ });
- let web_config = WebConfig::from_session(server_id, port, &session);
+ let server = Server::new(Arc::clone(&session));
- println!("Server listening on port {}", port);
+ println!("Server listening on port 34872");
- web::start(web_config);
-}
+ server.listen(34872);
+}
\ No newline at end of file
diff --git a/server/src/file_route.rs b/server/src/file_route.rs
deleted file mode 100644
index a691034e..00000000
--- a/server/src/file_route.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-use std::path::{Path, PathBuf, Component};
-
-use partition::Partition;
-
-// TODO: Change backing data structure to use a single allocation with slices
-// taken out of it for each portion
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct FileRoute {
- pub partition: String,
- pub route: Vec,
-}
-
-impl FileRoute {
- pub fn from_path(path: &Path, partition: &Partition) -> Option {
- assert!(path.is_absolute());
- assert!(path.starts_with(&partition.path));
-
- let relative_path = path.strip_prefix(&partition.path).ok()?;
- let mut route = Vec::new();
-
- for component in relative_path.components() {
- match component {
- Component::Normal(piece) => {
- route.push(piece.to_string_lossy().into_owned());
- },
- _ => panic!("Unexpected path component: {:?}", component),
- }
- }
-
- Some(FileRoute {
- partition: partition.name.clone(),
- route,
- })
- }
-
- pub fn parent(&self) -> Option {
- if self.route.len() == 0 {
- return None;
- }
-
- let mut new_route = self.route.clone();
- new_route.pop();
-
- Some(FileRoute {
- partition: self.partition.clone(),
- route: new_route,
- })
- }
-
- /// Creates a PathBuf out of the `FileRoute` based on the given partition
- /// `Path`.
- pub fn to_path_buf(&self, partition_path: &Path) -> PathBuf {
- let mut result = partition_path.to_path_buf();
-
- for route_piece in &self.route {
- result.push(route_piece);
- }
-
- result
- }
-
- /// Creates a version of the FileRoute with the given extra pieces appended
- /// to the end.
- pub fn extended_with(&self, pieces: &[&str]) -> FileRoute {
- let mut result = self.clone();
-
- for piece in pieces {
- result.route.push(piece.to_string());
- }
-
- result
- }
-
- pub fn file_name(&self, partition: &Partition) -> String {
- if self.route.len() == 0 {
- partition.path.file_name().unwrap().to_str().unwrap().to_string()
- } else {
- self.route.last().unwrap().clone()
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[cfg(windows)]
- const ROOT_PATH: &'static str = "C:\\";
-
- #[cfg(not(windows))]
- const ROOT_PATH: &'static str = "/";
-
- #[test]
- fn from_path_empty() {
- let path = Path::new(ROOT_PATH).join("a/b/c");
-
- let partition = Partition {
- name: "foo".to_string(),
- path: path.clone(),
- target: vec![],
- };
-
- let route = FileRoute::from_path(&path, &partition);
-
- assert_eq!(route, Some(FileRoute {
- partition: "foo".to_string(),
- route: vec![],
- }));
- }
-
- #[test]
- fn from_path_non_empty() {
- let partition_path = Path::new(ROOT_PATH).join("a/b/c");
-
- let inside_path = partition_path.join("d");
-
- let partition = Partition {
- name: "bar".to_string(),
- path: partition_path,
- target: vec![],
- };
-
- let route = FileRoute::from_path(&inside_path, &partition);
-
- assert_eq!(route, Some(FileRoute {
- partition: "bar".to_string(),
- route: vec!["d".to_string()],
- }));
- }
-
- #[test]
- fn file_name_empty_route() {
- let partition_path = Path::new(ROOT_PATH).join("a/b/c");
-
- let partition = Partition {
- name: "bar".to_string(),
- path: partition_path,
- target: vec![],
- };
-
- let route = FileRoute {
- partition: "bar".to_string(),
- route: vec![],
- };
-
- assert_eq!(route.file_name(&partition), "c");
- }
-
- #[test]
- fn file_name_non_empty_route() {
- let partition_path = Path::new(ROOT_PATH).join("a/b/c");
-
- let partition = Partition {
- name: "bar".to_string(),
- path: partition_path,
- target: vec![],
- };
-
- let route = FileRoute {
- partition: "bar".to_string(),
- route: vec!["foo".to_string(), "hello.lua".to_string()],
- };
-
- assert_eq!(route.file_name(&partition), "hello.lua");
- }
-}
\ No newline at end of file
diff --git a/server/src/id.rs b/server/src/id.rs
index a27a9d8c..98144cfa 100644
--- a/server/src/id.rs
+++ b/server/src/id.rs
@@ -18,4 +18,4 @@ fn it_gives_unique_numbers() {
let b = get_id();
assert!(a != b);
-}
+}
\ No newline at end of file
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 2f806548..315d266c 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -11,17 +11,13 @@ extern crate regex;
extern crate tempfile;
pub mod commands;
-pub mod file_route;
pub mod id;
-pub mod message_session;
-pub mod partition;
-pub mod partition_watcher;
+pub mod message_queue;
pub mod pathext;
pub mod project;
pub mod rbx;
-pub mod rbx_session;
-pub mod session;
-pub mod vfs_session;
-pub mod web;
-pub mod web_util;
pub mod roblox_studio;
+pub mod session;
+pub mod vfs;
+pub mod web;
+pub mod web_util;
\ No newline at end of file
diff --git a/server/src/message_session.rs b/server/src/message_queue.rs
similarity index 55%
rename from server/src/message_session.rs
rename to server/src/message_queue.rs
index 85b2aa32..1029c7e1 100644
--- a/server/src/message_session.rs
+++ b/server/src/message_queue.rs
@@ -1,5 +1,5 @@
use std::collections::HashMap;
-use std::sync::{mpsc, Arc, RwLock, Mutex};
+use std::sync::{mpsc, RwLock, Mutex};
use id::{Id, get_id};
@@ -11,17 +11,16 @@ pub enum Message {
},
}
-#[derive(Clone)]
-pub struct MessageSession {
- pub messages: Arc>>,
- pub message_listeners: Arc>>>,
+pub struct MessageQueue {
+ messages: RwLock>,
+ message_listeners: Mutex>>,
}
-impl MessageSession {
- pub fn new() -> MessageSession {
- MessageSession {
- messages: Arc::new(RwLock::new(Vec::new())),
- message_listeners: Arc::new(Mutex::new(HashMap::new())),
+impl MessageQueue {
+ pub fn new() -> MessageQueue {
+ MessageQueue {
+ messages: RwLock::new(Vec::new()),
+ message_listeners: Mutex::new(HashMap::new()),
}
}
@@ -58,7 +57,20 @@ impl MessageSession {
}
}
- pub fn get_message_cursor(&self) -> i32 {
- self.messages.read().unwrap().len() as i32 - 1
+ pub fn get_message_cursor(&self) -> u32 {
+ self.messages.read().unwrap().len() as u32
}
-}
+
+ pub fn get_messages_since(&self, cursor: u32) -> (u32, Vec) {
+ let messages = self.messages.read().unwrap();
+
+ let current_cursor = messages.len() as u32;
+
+ // Cursor is out of bounds or there are no new messages
+ if cursor >= current_cursor {
+ return (current_cursor, Vec::new());
+ }
+
+ (current_cursor, messages[(cursor as usize)..].to_vec())
+ }
+}
\ No newline at end of file
diff --git a/server/src/partition.rs b/server/src/partition.rs
deleted file mode 100644
index 9ef66664..00000000
--- a/server/src/partition.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-use std::path::PathBuf;
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct Partition {
- /// The unique name of this partition, used for debugging.
- pub name: String,
-
- /// The path on the filesystem that this partition maps to.
- pub path: PathBuf,
-
- /// The route to the Roblox instance that this partition maps to.
- pub target: Vec,
-}
diff --git a/server/src/partition_watcher.rs b/server/src/partition_watcher.rs
deleted file mode 100644
index 5885bb74..00000000
--- a/server/src/partition_watcher.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use std::sync::mpsc::{channel, Sender};
-use std::time::Duration;
-use std::thread;
-
-use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher, watcher};
-
-use partition::Partition;
-use vfs_session::FileChange;
-use file_route::FileRoute;
-
-const WATCH_TIMEOUT_MS: u64 = 100;
-
-pub struct PartitionWatcher {
- pub watcher: RecommendedWatcher,
-}
-
-impl PartitionWatcher {
- pub fn start_new(partition: Partition, tx: Sender) -> PartitionWatcher {
- let (watch_tx, watch_rx) = channel();
-
- let mut watcher = watcher(watch_tx, Duration::from_millis(WATCH_TIMEOUT_MS)).unwrap();
-
- watcher.watch(&partition.path, RecursiveMode::Recursive).unwrap();
-
- thread::spawn(move || {
- loop {
- match watch_rx.recv() {
- Ok(event) => {
- let file_change = match event {
- DebouncedEvent::Create(path) => {
- let route = FileRoute::from_path(&path, &partition).unwrap();
- FileChange::Created(route)
- },
- DebouncedEvent::Write(path) => {
- let route = FileRoute::from_path(&path, &partition).unwrap();
- FileChange::Updated(route)
- },
- DebouncedEvent::Remove(path) => {
- let route = FileRoute::from_path(&path, &partition).unwrap();
- FileChange::Deleted(route)
- },
- DebouncedEvent::Rename(from_path, to_path) => {
- let from_route = FileRoute::from_path(&from_path, &partition).unwrap();
- let to_route = FileRoute::from_path(&to_path, &partition).unwrap();
- FileChange::Moved(from_route, to_route)
- },
- _ => continue,
- };
-
- match tx.send(file_change) {
- Ok(_) => {},
- Err(_) => break,
- }
- },
- Err(_) => break,
- };
- }
- });
-
- PartitionWatcher {
- watcher,
- }
- }
-
- pub fn stop(self) {
- }
-}
diff --git a/server/src/pathext.rs b/server/src/pathext.rs
index 0b4c0f79..0b257cc8 100644
--- a/server/src/pathext.rs
+++ b/server/src/pathext.rs
@@ -24,4 +24,4 @@ where
} else {
root.join(value)
}
-}
+}
\ No newline at end of file
diff --git a/server/src/project.rs b/server/src/project.rs
index b0b95de7..b0a39e5a 100644
--- a/server/src/project.rs
+++ b/server/src/project.rs
@@ -1,246 +1,223 @@
-use std::collections::HashMap;
-use std::fmt;
-use std::fs::{self, File};
-use std::io::{Read, Write};
-use std::path::{Path, PathBuf};
-
-use rand::{self, Rng};
-
+use std::{
+ collections::HashMap,
+ fmt,
+ fs,
+ io,
+ path::{Path, PathBuf},
+};
use serde_json;
-use partition::Partition;
+pub static PROJECT_FILENAME: &'static str = "roblox-project.json";
-pub static PROJECT_FILENAME: &'static str = "rojo.json";
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(untagged)]
+enum SourceProjectNode {
+ Regular {
+ #[serde(rename = "$className")]
+ class_name: String,
-#[derive(Debug)]
-pub enum ProjectLoadError {
- DidNotExist(PathBuf),
- FailedToOpen(PathBuf),
- FailedToRead(PathBuf),
- InvalidJson(PathBuf, serde_json::Error),
+ // #[serde(rename = "$ignoreUnknown", default = "false")]
+ // ignore_unknown: bool,
+
+ #[serde(flatten)]
+ children: HashMap,
+ },
+ SyncPoint {
+ #[serde(rename = "$path")]
+ path: String,
+ }
}
-impl fmt::Display for ProjectLoadError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+impl SourceProjectNode {
+ pub fn into_project_node(self, project_file_location: &Path) -> ProjectNode {
match self {
- &ProjectLoadError::InvalidJson(ref project_path, ref serde_err) => {
- write!(f, "Found invalid JSON reading project: {}\nError: {}", project_path.display(), serde_err)
+ SourceProjectNode::Regular { class_name, mut children } => {
+ let mut new_children = HashMap::new();
+
+ for (node_name, node) in children.drain() {
+ new_children.insert(node_name, node.into_project_node(project_file_location));
+ }
+
+ ProjectNode::Regular {
+ class_name,
+ children: new_children,
+ }
},
- &ProjectLoadError::FailedToOpen(ref project_path) |
- &ProjectLoadError::FailedToRead(ref project_path) => {
- write!(f, "Found project file, but failed to read it: {}", project_path.display())
- },
- &ProjectLoadError::DidNotExist(ref project_path) => {
- write!(f, "Could not locate a project file at {}.\nUse 'rojo init' to create one.", project_path.display())
- },
- }
- }
-}
+ SourceProjectNode::SyncPoint { path: source_path } => {
+ let path = if Path::new(&source_path).is_absolute() {
+ PathBuf::from(source_path)
+ } else {
+ let project_folder_location = project_file_location.parent().unwrap();
+ project_folder_location.join(source_path)
+ };
-#[derive(Debug)]
-pub enum ProjectSaveError {
- FailedToCreate,
-}
-
-#[derive(Debug)]
-pub enum ProjectInitError {
- AlreadyExists,
- FailedToCreate,
- FailedToWrite,
-}
-
-impl fmt::Display for ProjectInitError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &ProjectInitError::AlreadyExists => {
- write!(f, "A project already exists at that location.")
- },
- &ProjectInitError::FailedToCreate |
- &ProjectInitError::FailedToWrite => {
- write!(f, "Failed to write to the given location.")
- },
- }
- }
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct SourceProjectPartition {
- /// A slash-separated path to a file or folder, relative to the project's
- /// directory.
- pub path: String,
-
- /// A dot-separated route to a Roblox instance, relative to game.
- pub target: String,
-}
-
-/// Represents a Rojo project in the format that's most convenient for users to
-/// edit. This should generally line up with `Project`, but can diverge when
-/// there's either compatibility shims or when the data structures that Rojo
-/// want are too verbose to write in JSON but easy to convert from something
-/// else.
-//
-/// Holds anything that can be configured with `rojo.json`.
-#[derive(Debug, Clone, Serialize, Deserialize)]
-#[serde(default, rename_all = "camelCase")]
-pub struct SourceProject {
- pub name: String,
- pub serve_port: u64,
- pub partitions: HashMap,
-}
-
-impl Default for SourceProject {
- fn default() -> SourceProject {
- SourceProject {
- name: "new-project".to_string(),
- serve_port: 8000,
- partitions: HashMap::new(),
- }
- }
-}
-
-/// Represents a Rojo project in the format that's convenient for Rojo to work
-/// with.
-#[derive(Debug, Clone)]
-pub struct Project {
- /// The path to the project file that this project is associated with.
- pub project_path: PathBuf,
-
- /// The name of this project, used for user-facing labels.
- pub name: String,
-
- /// The port that this project will run a web server on.
- pub serve_port: u64,
-
- /// All of the project's partitions, laid out in an expanded way.
- pub partitions: HashMap,
-}
-
-impl Project {
- fn from_source_project(source_project: SourceProject, project_path: PathBuf) -> Project {
- let mut partitions = HashMap::new();
-
- {
- let project_directory = project_path.parent().unwrap();
-
- for (partition_name, partition) in source_project.partitions.into_iter() {
- let path = project_directory.join(&partition.path);
- let target = partition.target
- .split(".")
- .map(String::from)
- .collect::>();
-
- partitions.insert(partition_name.clone(), Partition {
+ ProjectNode::SyncPoint {
path,
- target,
- name: partition_name,
- });
- }
+ }
+ },
+ }
+ }
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct SourceProject {
+ name: String,
+ tree: HashMap,
+}
+
+impl SourceProject {
+ pub fn into_project(mut self, project_file_location: &Path) -> Project {
+ let mut tree = HashMap::new();
+
+ for (node_name, node) in self.tree.drain() {
+ tree.insert(node_name, node.into_project_node(project_file_location));
}
Project {
- project_path,
- name: source_project.name,
- serve_port: source_project.serve_port,
- partitions,
+ name: self.name,
+ tree: tree,
+ file_location: PathBuf::from(project_file_location),
}
}
-
- fn as_source_project(&self) -> SourceProject {
- let mut partitions = HashMap::new();
-
- for partition in self.partitions.values() {
- let path = partition.path.strip_prefix(&self.project_path)
- .unwrap_or_else(|_| &partition.path)
- .to_str()
- .unwrap()
- .to_string();
-
- let target = partition.target.join(".");
-
- partitions.insert(partition.name.clone(), SourceProjectPartition {
- path,
- target,
- });
- }
-
- SourceProject {
- partitions,
- name: self.name.clone(),
- serve_port: self.serve_port,
- }
- }
-
- /// Initializes a new project inside the given folder path.
- pub fn init>(location: T) -> Result {
- let location = location.as_ref();
- let project_path = location.join(PROJECT_FILENAME);
-
- // We abort if the project file already exists.
- fs::metadata(&project_path)
- .map_err(|_| ProjectInitError::AlreadyExists)?;
-
- let mut file = File::create(&project_path)
- .map_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() {
- Some(v) => v.to_string_lossy().into_owned(),
- None => "new-project".to_string(),
- };
-
- // Generate a random port to run the server on.
- let serve_port = rand::thread_rng().gen_range(2000, 49151);
-
- // Configure the project with all of the values we know so far.
- let source_project = SourceProject {
- name,
- serve_port,
- partitions: HashMap::new(),
- };
- let serialized = serde_json::to_string_pretty(&source_project).unwrap();
-
- file.write(serialized.as_bytes())
- .map_err(|_| ProjectInitError::FailedToWrite)?;
-
- Ok(Project::from_source_project(source_project, project_path))
- }
-
- /// Attempts to load a project from the file named PROJECT_FILENAME from the
- /// given folder.
- pub fn load>(location: T) -> Result {
- let project_path = location.as_ref().join(Path::new(PROJECT_FILENAME));
-
- fs::metadata(&project_path)
- .map_err(|_| ProjectLoadError::DidNotExist(project_path.clone()))?;
-
- let mut file = File::open(&project_path)
- .map_err(|_| ProjectLoadError::FailedToOpen(project_path.clone()))?;
-
- let mut contents = String::new();
-
- file.read_to_string(&mut contents)
- .map_err(|_| ProjectLoadError::FailedToRead(project_path.clone()))?;
-
- let source_project = serde_json::from_str(&contents)
- .map_err(|e| ProjectLoadError::InvalidJson(project_path.clone(), e))?;
-
- Ok(Project::from_source_project(source_project, project_path))
- }
-
- /// Saves the given project file to the given folder with the appropriate name.
- pub fn save>(&self, location: T) -> Result<(), ProjectSaveError> {
- let project_path = location.as_ref().join(Path::new(PROJECT_FILENAME));
-
- let mut file = File::create(&project_path)
- .map_err(|_| ProjectSaveError::FailedToCreate)?;
-
- let source_project = self.as_source_project();
- let serialized = serde_json::to_string_pretty(&source_project).unwrap();
-
- file.write(serialized.as_bytes()).unwrap();
-
- Ok(())
- }
}
+
+#[derive(Debug)]
+pub enum ProjectLoadExactError {
+ IoError(io::Error),
+ JsonError(serde_json::Error),
+}
+
+impl fmt::Display for ProjectLoadExactError {
+ fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ ProjectLoadExactError::IoError(inner) => write!(output, "{}", inner),
+ ProjectLoadExactError::JsonError(inner) => write!(output, "{}", inner),
+ }
+ }
+}
+
+#[derive(Debug)]
+pub enum ProjectInitError {}
+
+impl fmt::Display for ProjectInitError {
+ fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
+ write!(output, "ProjectInitError")
+ }
+}
+
+#[derive(Debug)]
+pub enum ProjectLoadFuzzyError {
+ NotFound,
+ IoError(io::Error),
+ JsonError(serde_json::Error),
+}
+
+impl From for ProjectLoadFuzzyError {
+ fn from(error: ProjectLoadExactError) -> ProjectLoadFuzzyError {
+ match error {
+ ProjectLoadExactError::IoError(inner) => ProjectLoadFuzzyError::IoError(inner),
+ ProjectLoadExactError::JsonError(inner) => ProjectLoadFuzzyError::JsonError(inner),
+ }
+ }
+}
+
+impl fmt::Display for ProjectLoadFuzzyError {
+ fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ ProjectLoadFuzzyError::NotFound => write!(output, "Project not found."),
+ ProjectLoadFuzzyError::IoError(inner) => write!(output, "{}", inner),
+ ProjectLoadFuzzyError::JsonError(inner) => write!(output, "{}", inner),
+ }
+ }
+}
+
+#[derive(Debug)]
+pub enum ProjectSaveError {}
+
+impl fmt::Display for ProjectSaveError {
+ fn fmt(&self, output: &mut fmt::Formatter) -> fmt::Result {
+ write!(output, "ProjectSaveError")
+ }
+}
+
+#[derive(Debug)]
+pub enum ProjectNode {
+ Regular {
+ class_name: String,
+ children: HashMap,
+
+ // ignore_unknown: bool,
+ },
+ SyncPoint {
+ path: PathBuf,
+ },
+}
+
+#[derive(Debug)]
+pub struct Project {
+ pub name: String,
+ pub tree: HashMap,
+ pub file_location: PathBuf,
+}
+
+impl Project {
+ pub fn init(_project_folder_location: &Path) -> Result<(), ProjectInitError> {
+ unimplemented!();
+ }
+
+ pub fn locate(start_location: &Path) -> Option {
+ // TODO: Check for specific error kinds, convert 'not found' to Result.
+ let location_metadata = fs::metadata(start_location).ok()?;
+
+ // If this is a file, we should assume it's the config we want
+ if location_metadata.is_file() {
+ return Some(start_location.to_path_buf());
+ } else if location_metadata.is_dir() {
+ let with_file = start_location.join(PROJECT_FILENAME);
+
+ match fs::metadata(&with_file) {
+ Ok(with_file_metadata) => {
+ if with_file_metadata.is_file() {
+ return Some(with_file);
+ } else {
+ return None;
+ }
+ },
+ Err(_) => {},
+ }
+ }
+
+ match start_location.parent() {
+ Some(parent_location) => Self::locate(parent_location),
+ None => None,
+ }
+ }
+
+ pub fn load_fuzzy(fuzzy_project_location: &Path) -> Result {
+ let project_path = Self::locate(fuzzy_project_location)
+ .ok_or(ProjectLoadFuzzyError::NotFound)?;
+
+ Self::load_exact(&project_path).map_err(From::from)
+ }
+
+ pub fn load_exact(project_file_location: &Path) -> Result {
+ let contents = fs::read_to_string(project_file_location)
+ .map_err(ProjectLoadExactError::IoError)?;
+
+ let parsed: SourceProject = serde_json::from_str(&contents)
+ .map_err(ProjectLoadExactError::JsonError)?;
+
+ Ok(parsed.into_project(project_file_location))
+ }
+
+ pub fn save(&self) -> Result<(), ProjectSaveError> {
+ let _source_project = self.to_source_project();
+
+ unimplemented!();
+ }
+
+ fn to_source_project(&self) -> SourceProject {
+ unimplemented!();
+ }
+}
\ No newline at end of file
diff --git a/server/src/rbx.rs b/server/src/rbx.rs
index e3437f3c..d3873cb7 100644
--- a/server/src/rbx.rs
+++ b/server/src/rbx.rs
@@ -1,7 +1,6 @@
-use std::borrow::Cow;
use std::collections::HashMap;
-use id::Id;
+use id::{Id, get_id};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type")]
@@ -23,46 +22,107 @@ pub struct RbxInstance {
/// Contains all other properties of an Instance.
pub properties: HashMap,
+ /// The unique ID of the instance
+ id: Id,
+
/// All of the children of this instance. Order is relevant to preserve!
- pub children: Vec,
+ children: Vec,
/// The parent of the instance, if there is one.
- pub parent: Option,
+ parent: Option,
}
-// This seems like a really bad idea?
-// Why isn't there a blanket impl for this for all T?
-impl<'a> From<&'a RbxInstance> for Cow<'a, RbxInstance> {
- fn from(instance: &'a RbxInstance) -> Cow<'a, RbxInstance> {
- Cow::Borrowed(instance)
+impl RbxInstance {
+ pub fn get_id(&self) -> Id {
+ self.id
+ }
+}
+
+pub struct Descendants<'a> {
+ tree: &'a RbxTree,
+ ids_to_visit: Vec,
+}
+
+impl<'a> Iterator for Descendants<'a> {
+ type Item = &'a RbxInstance;
+
+ fn next(&mut self) -> Option {
+ loop {
+ let id = match self.ids_to_visit.pop() {
+ Some(id) => id,
+ None => break,
+ };
+
+ match self.tree.get_instance(id) {
+ Some(instance) => {
+ for child_id in &instance.children {
+ self.ids_to_visit.push(*child_id);
+ }
+
+ return Some(instance);
+ },
+ None => continue,
+ }
+ }
+
+ None
}
}
pub struct RbxTree {
instances: HashMap,
+ pub root_instance_id: Id,
}
impl RbxTree {
pub fn new() -> RbxTree {
+ let root_instance_id = get_id();
+ let root_instance = RbxInstance {
+ name: "game".to_string(),
+ class_name: "DataModel".to_string(),
+ properties: HashMap::new(),
+ id: root_instance_id,
+ children: Vec::new(),
+ parent: None,
+ };
+
+ let mut instances = HashMap::new();
+ instances.insert(root_instance_id, root_instance);
+
RbxTree {
- instances: HashMap::new(),
+ instances,
+ root_instance_id,
}
}
+ pub fn get_instance(&self, id: Id) -> Option<&RbxInstance> {
+ self.instances.get(&id)
+ }
+
pub fn get_all_instances(&self) -> &HashMap {
&self.instances
}
- pub fn insert_instance(&mut self, id: Id, instance: RbxInstance) {
- if let Some(parent_id) = instance.parent {
- if let Some(mut parent) = self.instances.get_mut(&parent_id) {
- if !parent.children.contains(&id) {
- parent.children.push(id);
+ pub fn insert_instance(&mut self, mut instance: RbxInstance) {
+ match instance.parent {
+ Some(parent_id) => {
+ match self.instances.get_mut(&parent_id) {
+ Some(mut parent) => {
+ if !parent.children.contains(&instance.id) {
+ parent.children.push(instance.id);
+ }
+ },
+ None => {
+ panic!("Tree consistency error, parent {} was not present in tree.", parent_id);
+ }
}
- }
+ },
+ None => {
+ instance.parent = Some(self.root_instance_id);
+ },
}
- self.instances.insert(id, instance);
+ self.instances.insert(instance.id, instance);
}
pub fn delete_instance(&mut self, id: Id) -> Vec {
@@ -101,27 +161,20 @@ impl RbxTree {
ids_deleted
}
- pub fn get_instance_and_descendants<'a, 'b, T>(&'a self, id: Id, output: &'b mut HashMap)
- where T: From<&'a RbxInstance>
- {
- let mut ids_to_visit = vec![id];
-
- loop {
- let id = match ids_to_visit.pop() {
- Some(id) => id,
- None => break,
- };
-
- match self.instances.get(&id) {
- Some(instance) => {
- output.insert(id, instance.into());
-
- for child_id in &instance.children {
- ids_to_visit.push(*child_id);
- }
- },
- None => continue,
- }
+ pub fn iter_descendants<'a>(&'a self, id: Id) -> Descendants<'a> {
+ match self.get_instance(id) {
+ Some(instance) => {
+ Descendants {
+ tree: self,
+ ids_to_visit: instance.children.clone(),
+ }
+ },
+ None => {
+ Descendants {
+ tree: self,
+ ids_to_visit: vec![],
+ }
+ },
}
}
-}
+}
\ No newline at end of file
diff --git a/server/src/rbx_session.rs b/server/src/rbx_session.rs
deleted file mode 100644
index 0abd25e8..00000000
--- a/server/src/rbx_session.rs
+++ /dev/null
@@ -1,306 +0,0 @@
-use std::collections::HashMap;
-use std::sync::{Arc, RwLock};
-
-use file_route::FileRoute;
-use id::{Id, get_id};
-use message_session::{Message, MessageSession};
-use partition::Partition;
-use project::Project;
-use rbx::{RbxInstance, RbxTree, RbxValue};
-use vfs_session::{VfsSession, FileItem, FileChange};
-
-static SERVICES: &'static [&'static str] = &[
- "Chat",
- "Lighting",
- "LocalizationService",
- "Players",
- "ReplicatedFirst",
- "ReplicatedStorage",
- "ServerScriptService",
- "ServerStorage",
- "SoundService",
- "StarterGui",
- "StarterPack",
- "StarterPlayer",
- "TestService",
- "Workspace",
-];
-
-fn get_partition_target_class_name(target: &[String]) -> &'static str {
- match target.len() {
- 1 => {
- let target_name = &target[0];
-
- for &service in SERVICES {
- if service == target_name {
- return service;
- }
- }
-
- "Folder"
- },
- 2 => {
- "Folder"
- },
- _ => "Folder",
- }
-}
-
-// TODO: Rethink data structure and insertion/update behavior. Maybe break some
-// pieces off into a new object?
-fn file_to_instances(
- file_item: &FileItem,
- partition: &Partition,
- tree: &mut RbxTree,
- instances_by_route: &mut HashMap,
- parent_id: Option,
-) -> (Id, Vec) {
- match file_item {
- FileItem::File { contents, route } => {
- let primary_id = match instances_by_route.get(&file_item.get_route()) {
- Some(&id) => id,
- None => {
- let id = get_id();
- instances_by_route.insert(route.clone(), id);
-
- id
- },
- };
-
- // This is placeholder logic; this whole function is!
- let (class_name, property_key, name) = {
- let file_name = match route.route.last() {
- Some(v) => v.to_string(),
- None => partition.path.file_name().unwrap().to_str().unwrap().to_string()
- };
-
- let use_partition_name = route.route.len() == 0;
-
- let partition_name = partition.target.last().unwrap();
-
- fn strip_suffix<'a>(source: &'a str, suffix: &'static str) -> String {
- source[..source.len() - suffix.len()].to_string()
- }
-
- if file_name.ends_with(".client.lua") {
- let name = if use_partition_name {
- partition_name.clone()
- } else {
- strip_suffix(&file_name, ".client.lua")
- };
-
- ("LocalScript", "Source", name)
- } else if file_name.ends_with(".server.lua") {
- let name = if use_partition_name {
- partition_name.clone()
- } else {
- strip_suffix(&file_name, ".server.lua")
- };
-
- ("Script", "Source", name)
- } else if file_name.ends_with(".lua") {
- let name = if use_partition_name {
- partition_name.clone()
- } else {
- strip_suffix(&file_name, ".lua")
- };
-
- ("ModuleScript", "Source", name)
- } else {
- let name = if use_partition_name {
- partition_name.clone()
- } else {
- file_name
- };
-
- // TODO: Error/warn/skip instead of falling back
- ("StringValue", "Value", name)
- }
- };
-
- let mut properties = HashMap::new();
- properties.insert(property_key.to_string(), RbxValue::String { value: contents.clone() });
-
- tree.insert_instance(primary_id, RbxInstance {
- name,
- class_name: class_name.to_string(),
- properties,
- children: Vec::new(),
- parent: parent_id,
- });
-
- (primary_id, vec![primary_id])
- },
- FileItem::Directory { children, route } => {
- let primary_id = match instances_by_route.get(&file_item.get_route()) {
- Some(&id) => id,
- None => {
- let id = get_id();
- instances_by_route.insert(route.clone(), id);
-
- id
- },
- };
-
- let mut child_ids = Vec::new();
-
- let mut changed_ids = vec![primary_id];
-
- for child_file_item in children.values() {
- let (child_id, mut child_changed_ids) = file_to_instances(child_file_item, partition, tree, instances_by_route, Some(primary_id));
-
- child_ids.push(child_id);
- changed_ids.push(child_id);
-
- // TODO: Should I stop using drain on Vecs of Copyable types?
- for id in child_changed_ids.drain(..) {
- changed_ids.push(id);
- }
- }
-
- let class_name = get_partition_target_class_name(&route.route).to_string();
-
- let name = if route.route.len() == 0 {
- partition.target.last().unwrap().clone()
- } else {
- route.file_name(partition)
- };
-
- tree.insert_instance(primary_id, RbxInstance {
- name,
- class_name,
- properties: HashMap::new(),
- children: child_ids,
- parent: parent_id,
- });
-
- (primary_id, changed_ids)
- },
- }
-}
-
-pub struct RbxSession {
- project: Project,
-
- vfs_session: Arc>,
-
- message_session: MessageSession,
-
- /// The RbxInstance that represents each partition.
- // TODO: Can this be removed in favor of instances_by_route?
- pub partition_instances: HashMap,
-
- /// Keeps track of all of the instances in the tree
- pub tree: RbxTree,
-
- /// A map from files in the VFS to instances loaded in the session.
- instances_by_route: HashMap,
-}
-
-impl RbxSession {
- pub fn new(project: Project, vfs_session: Arc>, message_session: MessageSession) -> RbxSession {
- RbxSession {
- project,
- vfs_session,
- message_session,
- partition_instances: HashMap::new(),
- tree: RbxTree::new(),
- instances_by_route: HashMap::new(),
- }
- }
-
- pub fn read_partitions(&mut self) {
- let vfs_session_arc = self.vfs_session.clone();
- let vfs_session = vfs_session_arc.read().unwrap();
-
- for partition in self.project.partitions.values() {
- let route = FileRoute {
- partition: partition.name.clone(),
- route: Vec::new(),
- };
- let file_item = vfs_session.get_by_route(&route).unwrap();
-
- let parent_id = match route.parent() {
- Some(parent_route) => match self.instances_by_route.get(&parent_route) {
- Some(&parent_id) => Some(parent_id),
- None => None,
- },
- None => None,
- };
-
- let (root_id, _) = file_to_instances(file_item, partition, &mut self.tree, &mut self.instances_by_route, parent_id);
-
- self.partition_instances.insert(partition.name.clone(), root_id);
- }
- }
-
- pub fn handle_change(&mut self, change: &FileChange) {
- let vfs_session_arc = self.vfs_session.clone();
- let vfs_session = vfs_session_arc.read().unwrap();
-
- match change {
- FileChange::Created(route) | FileChange::Updated(route) => {
- let file_item = vfs_session.get_by_route(route).unwrap();
- let partition = self.project.partitions.get(&route.partition).unwrap();
-
- let parent_id = match route.parent() {
- Some(parent_route) => match self.instances_by_route.get(&parent_route) {
- Some(&parent_id) => Some(parent_id),
- None => None,
- },
- None => None,
- };
-
- let (_, changed_ids) = file_to_instances(file_item, partition, &mut self.tree, &mut self.instances_by_route, parent_id);
-
- let messages = changed_ids
- .iter()
- .map(|&id| Message::InstanceChanged { id })
- .collect::>();
-
- self.message_session.push_messages(&messages);
- },
- FileChange::Deleted(route) => {
- match self.instances_by_route.get(route) {
- Some(&id) => {
- self.tree.delete_instance(id);
- self.instances_by_route.remove(route);
- self.message_session.push_messages(&[Message::InstanceChanged { id }]);
- },
- None => (),
- }
- },
- FileChange::Moved(from_route, to_route) => {
- let mut messages = Vec::new();
-
- match self.instances_by_route.get(from_route) {
- Some(&id) => {
- self.tree.delete_instance(id);
- self.instances_by_route.remove(from_route);
- messages.push(Message::InstanceChanged { id });
- },
- None => (),
- }
-
- let file_item = vfs_session.get_by_route(to_route).unwrap();
- let partition = self.project.partitions.get(&to_route.partition).unwrap();
-
- let parent_id = match to_route.parent() {
- Some(parent_route) => match self.instances_by_route.get(&parent_route) {
- Some(&parent_id) => Some(parent_id),
- None => None,
- },
- None => None,
- };
-
- let (_, changed_ids) = file_to_instances(file_item, partition, &mut self.tree, &mut self.instances_by_route, parent_id);
-
- for id in changed_ids {
- messages.push(Message::InstanceChanged { id });
- }
-
- self.message_session.push_messages(&messages);
- },
- }
- }
-}
diff --git a/server/src/session.rs b/server/src/session.rs
index 55341bb3..b1e9c7c8 100644
--- a/server/src/session.rs
+++ b/server/src/session.rs
@@ -1,95 +1,121 @@
-use std::sync::{mpsc, Arc, RwLock};
-use std::thread;
+use std::{
+ sync::{Arc, RwLock, Mutex, mpsc},
+ thread,
+ io,
+ time::Duration,
+};
-use message_session::MessageSession;
-use partition_watcher::PartitionWatcher;
-use project::Project;
-use rbx_session::RbxSession;
-use vfs_session::VfsSession;
+use rand;
-/// Stub trait for middleware
-trait Middleware {
-}
+use notify::{
+ self,
+ DebouncedEvent,
+ RecommendedWatcher,
+ RecursiveMode,
+ Watcher,
+};
+
+use ::{
+ message_queue::MessageQueue,
+ rbx::RbxTree,
+ project::{Project, ProjectNode},
+ vfs::Vfs,
+};
+
+const WATCH_TIMEOUT_MS: u64 = 100;
pub struct Session {
- pub project: Project,
- vfs_session: Arc>,
- rbx_session: Arc>,
- message_session: MessageSession,
- watchers: Vec,
+ project: Project,
+ pub session_id: String,
+ pub message_queue: Arc,
+ pub tree: Arc>,
+ vfs: Arc>,
+ watchers: Vec,
}
impl Session {
pub fn new(project: Project) -> Session {
- let message_session = MessageSession::new();
- let vfs_session = Arc::new(RwLock::new(VfsSession::new(project.clone())));
- let rbx_session = Arc::new(RwLock::new(RbxSession::new(project.clone(), vfs_session.clone(), message_session.clone())));
+ let session_id = rand::random::().to_string();
Session {
- vfs_session,
- rbx_session,
- watchers: Vec::new(),
- message_session,
+ session_id,
project,
+ message_queue: Arc::new(MessageQueue::new()),
+ tree: Arc::new(RwLock::new(RbxTree::new())),
+ vfs: Arc::new(Mutex::new(Vfs::new())),
+ watchers: Vec::new(),
}
}
- pub fn start(&mut self) {
- {
- let mut vfs_session = self.vfs_session.write().unwrap();
- vfs_session.read_partitions();
- }
-
- {
- let mut rbx_session = self.rbx_session.write().unwrap();
- rbx_session.read_partitions();
- }
-
- let (tx, rx) = mpsc::channel();
-
- for partition in self.project.partitions.values() {
- let watcher = PartitionWatcher::start_new(partition.clone(), tx.clone());
-
- self.watchers.push(watcher);
- }
-
- {
- let vfs_session = self.vfs_session.clone();
- let rbx_session = self.rbx_session.clone();
-
- thread::spawn(move || {
- loop {
- match rx.recv() {
- Ok(change) => {
- {
- let mut vfs_session = vfs_session.write().unwrap();
- vfs_session.handle_change(&change);
- }
-
- {
- let mut rbx_session = rbx_session.write().unwrap();
- rbx_session.handle_change(&change);
- }
- },
- Err(_) => break,
+ pub fn start(&mut self) -> io::Result<()> {
+ fn add_sync_points(vfs: &mut Vfs, project_node: &ProjectNode) -> io::Result<()> {
+ match project_node {
+ ProjectNode::Regular { children, .. } => {
+ for child in children.values() {
+ add_sync_points(vfs, child)?;
}
- }
- });
+ },
+ ProjectNode::SyncPoint { path } => {
+ vfs.add_root(path)?;
+ },
+ }
+
+ Ok(())
}
+
+ {
+ let mut vfs = self.vfs.lock().unwrap();
+
+ for child in self.project.tree.values() {
+ add_sync_points(&mut vfs, child)?;
+ }
+
+ for root in vfs.get_roots() {
+ println!("Watching {}", root.display());
+
+ let (watch_tx, watch_rx) = mpsc::channel();
+
+ let mut watcher = notify::watcher(watch_tx, Duration::from_millis(WATCH_TIMEOUT_MS)).unwrap();
+
+ watcher.watch(root, RecursiveMode::Recursive).unwrap();
+ self.watchers.push(watcher);
+
+ let vfs = Arc::clone(&self.vfs);
+
+ thread::spawn(move || {
+ println!("Thread started");
+ loop {
+ match watch_rx.recv() {
+ Ok(event) => {
+ match event {
+ DebouncedEvent::Create(path) | DebouncedEvent::Write(path) => {
+ let mut vfs = vfs.lock().unwrap();
+ vfs.add_or_update(&path).unwrap();
+ },
+ DebouncedEvent::Remove(path) => {
+ let mut vfs = vfs.lock().unwrap();
+ vfs.remove(&path);
+ },
+ DebouncedEvent::Rename(from_path, to_path) => {
+ let mut vfs = vfs.lock().unwrap();
+ vfs.remove(&from_path);
+ vfs.add_or_update(&to_path).unwrap();
+ },
+ _ => continue,
+ };
+ },
+ Err(_) => break,
+ };
+ }
+ println!("Thread stopped");
+ });
+ }
+ }
+
+ Ok(())
}
- pub fn stop(self) {
+ pub fn get_project(&self) -> &Project {
+ &self.project
}
-
- pub fn get_vfs_session(&self) -> Arc> {
- self.vfs_session.clone()
- }
-
- pub fn get_rbx_session(&self) -> Arc> {
- self.rbx_session.clone()
- }
-
- pub fn get_message_session(&self) -> MessageSession {
- self.message_session.clone()
- }
-}
+}
\ No newline at end of file
diff --git a/server/src/vfs.rs b/server/src/vfs.rs
new file mode 100644
index 00000000..7ac6e0f4
--- /dev/null
+++ b/server/src/vfs.rs
@@ -0,0 +1,139 @@
+use std::{
+ collections::{HashMap, HashSet},
+ path::{Path, PathBuf},
+ fs,
+ io,
+};
+
+#[derive(Debug)]
+pub struct Vfs {
+ contents: HashMap>,
+ items: HashMap,
+ roots: HashSet,
+}
+
+impl Vfs {
+ pub fn new() -> Vfs {
+ Vfs {
+ contents: HashMap::new(),
+ items: HashMap::new(),
+ roots: HashSet::new(),
+ }
+ }
+
+ pub fn add_root<'a, 'b>(&'a mut self, root_path: &'b Path) -> io::Result<&'a VfsItem> {
+ debug_assert!(root_path.is_absolute());
+
+ self.roots.insert(root_path.to_path_buf());
+
+ VfsItem::get(self, root_path)
+ }
+
+ pub fn get_roots(&self) -> &HashSet {
+ &self.roots
+ }
+
+ pub fn get(&mut self, path: &Path) -> Option<&VfsItem> {
+ debug_assert!(path.is_absolute());
+ debug_assert!(self.is_valid_path(path));
+
+ self.items.get(path)
+ }
+
+ pub fn remove(&mut self, path: &Path) {
+ debug_assert!(path.is_absolute());
+ debug_assert!(self.is_valid_path(path));
+
+ match self.items.remove(path) {
+ Some(item) => match item {
+ VfsItem::File(_) => {
+ self.contents.remove(path);
+ },
+ VfsItem::Directory(VfsDirectory { children, .. }) => {
+ for child_path in &children {
+ self.remove(child_path);
+ }
+ },
+ },
+ None => {},
+ }
+ }
+
+ pub fn add_or_update<'a, 'b>(&'a mut self, path: &'b Path) -> io::Result<&'a VfsItem> {
+ debug_assert!(path.is_absolute());
+ debug_assert!(self.is_valid_path(path));
+
+ VfsItem::get(self, path)
+ }
+
+ fn is_valid_path(&self, path: &Path) -> bool {
+ let mut is_valid_path = false;
+
+ for root_path in &self.roots {
+ if path.starts_with(root_path) {
+ is_valid_path = true;
+ break;
+ }
+ }
+
+ is_valid_path
+ }
+}
+
+#[derive(Debug)]
+pub struct VfsFile {
+ path: PathBuf,
+}
+
+#[derive(Debug)]
+pub struct VfsDirectory {
+ path: PathBuf,
+ children: HashSet,
+}
+
+#[derive(Debug)]
+pub enum VfsItem {
+ File(VfsFile),
+ Directory(VfsDirectory),
+}
+
+impl VfsItem {
+ fn get<'a, 'b>(vfs: &'a mut Vfs, root_path: &'b Path) -> io::Result<&'a VfsItem> {
+ let metadata = fs::metadata(root_path)?;
+
+ if metadata.is_file() {
+ let item = VfsItem::File(VfsFile {
+ path: root_path.to_path_buf(),
+ });
+
+ vfs.items.insert(root_path.to_path_buf(), item);
+
+ let contents = fs::read(root_path)?;
+ vfs.contents.insert(root_path.to_path_buf(), contents);
+
+ Ok(vfs.items.get(root_path).unwrap())
+ } else if metadata.is_dir() {
+ let mut children = HashSet::new();
+
+ for entry in fs::read_dir(root_path)? {
+ let entry = entry?;
+ let path = entry.path();
+
+ VfsItem::get(vfs, &path)?;
+
+ children.insert(path);
+ }
+
+ let item = VfsItem::Directory(VfsDirectory {
+ path: root_path.to_path_buf(),
+ children,
+ });
+
+ vfs.items.insert(root_path.to_path_buf(), item);
+
+ Ok(vfs.items.get(root_path).unwrap())
+ } else {
+ unimplemented!();
+ }
+ }
+}
\ No newline at end of file
diff --git a/server/src/vfs_session.rs b/server/src/vfs_session.rs
deleted file mode 100644
index c4dc3e0b..00000000
--- a/server/src/vfs_session.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-use std::collections::HashMap;
-use std::io::Read;
-use std::fs::{self, File};
-use std::mem;
-
-use file_route::FileRoute;
-use project::Project;
-
-/// Represents a file or directory that has been read from the filesystem.
-#[derive(Debug, Clone)]
-pub enum FileItem {
- File {
- contents: String,
- route: FileRoute,
- },
- Directory {
- children: HashMap,
- route: FileRoute,
- },
-}
-
-impl FileItem {
- pub fn get_route(&self) -> &FileRoute {
- match self {
- FileItem::File { route, .. } => route,
- FileItem::Directory { route, .. } => route,
- }
- }
-}
-
-#[derive(Debug, Clone)]
-pub enum FileChange {
- Created(FileRoute),
- Deleted(FileRoute),
- Updated(FileRoute),
- Moved(FileRoute, FileRoute),
-}
-
-pub struct VfsSession {
- pub project: Project,
-
- /// The in-memory files associated with each partition.
- pub partition_files: HashMap,
-}
-
-impl VfsSession {
- pub fn new(project: Project) -> VfsSession {
- VfsSession {
- project,
- partition_files: HashMap::new(),
- }
- }
-
- pub fn read_partitions(&mut self) {
- for partition_name in self.project.partitions.keys() {
- let route = FileRoute {
- partition: partition_name.clone(),
- route: Vec::new(),
- };
-
- let file_item = self.read(&route).expect("Couldn't load partitions");
-
- self.partition_files.insert(partition_name.clone(), file_item);
- }
- }
-
- pub fn handle_change(&mut self, change: &FileChange) -> Option<()> {
- match change {
- FileChange::Created(route) | FileChange::Updated(route) => {
- let new_item = self.read(&route).ok()?;
- self.set_file_item(new_item);
- },
- FileChange::Deleted(route) => {
- self.delete_route(&route);
- },
- FileChange::Moved(from_route, to_route) => {
- let new_item = self.read(&to_route).ok()?;
- self.delete_route(&from_route);
- self.set_file_item(new_item);
- },
- }
-
- None
- }
-
- pub fn get_by_route(&self, route: &FileRoute) -> Option<&FileItem> {
- let partition = self.partition_files.get(&route.partition)?;
- let mut current = partition;
-
- for piece in &route.route {
- match current {
- FileItem::File { .. } => return None,
- FileItem::Directory { children, .. } => {
- current = children.get(piece)?;
- },
- }
- }
-
- Some(current)
- }
-
- pub fn get_by_route_mut(&mut self, route: &FileRoute) -> Option<&mut FileItem> {
- let mut current = self.partition_files.get_mut(&route.partition)?;
-
- for piece in &route.route {
- let mut next = match { current } {
- FileItem::File { .. } => return None,
- FileItem::Directory { children, .. } => {
- children.get_mut(piece)?
- },
- };
-
- current = next;
- }
-
- Some(current)
- }
-
- pub fn set_file_item(&mut self, item: FileItem) {
- match self.get_by_route_mut(item.get_route()) {
- Some(existing) => {
- mem::replace(existing, item);
- return;
- },
- None => {},
- }
-
- if item.get_route().route.len() > 0 {
- let mut parent_route = item.get_route().clone();
- let child_name = parent_route.route.pop().unwrap();
-
- let mut parent_children = HashMap::new();
- parent_children.insert(child_name, item);
-
- let parent_item = FileItem::Directory {
- route: parent_route,
- children: parent_children,
- };
-
- self.set_file_item(parent_item);
- } else {
- self.partition_files.insert(item.get_route().partition.clone(), item);
- }
- }
-
- pub fn delete_route(&mut self, route: &FileRoute) -> Option<()> {
- if route.route.len() == 0 {
- self.partition_files.remove(&route.partition);
- return Some(());
- }
-
- let mut current = self.partition_files.get_mut(&route.partition)?;
-
- for i in 0..(route.route.len() - 1) {
- let piece = &route.route[i];
-
- let mut next = match { current } {
- FileItem::File { .. } => return None,
- FileItem::Directory { children, .. } => {
- children.get_mut(piece)?
- },
- };
-
- current = next;
- }
-
- match current {
- FileItem::Directory { children, .. } => {
- children.remove(route.route.last().unwrap().as_str());
- },
- _ => {},
- }
-
- Some(())
- }
-
- fn read(&self, route: &FileRoute) -> Result {
- let partition_path = &self.project.partitions.get(&route.partition)
- .ok_or(())?.path;
- let path = route.to_path_buf(partition_path);
-
- let metadata = fs::metadata(path)
- .map_err(|_| ())?;
-
- if metadata.is_dir() {
- self.read_directory(route)
- } else if metadata.is_file() {
- self.read_file(route)
- } else {
- Err(())
- }
- }
-
- fn read_file(&self, route: &FileRoute) -> Result {
- let partition_path = &self.project.partitions.get(&route.partition)
- .ok_or(())?.path;
- let path = route.to_path_buf(partition_path);
-
- let mut file = File::open(path)
- .map_err(|_| ())?;
-
- let mut contents = String::new();
-
- file.read_to_string(&mut contents)
- .map_err(|_| ())?;
-
- Ok(FileItem::File {
- contents,
- route: route.clone(),
- })
- }
-
- fn read_directory(&self, route: &FileRoute) -> Result {
- let partition_path = &self.project.partitions.get(&route.partition)
- .ok_or(())?.path;
- let path = route.to_path_buf(partition_path);
-
- let reader = fs::read_dir(path)
- .map_err(|_| ())?;
-
- let mut children = HashMap::new();
-
- for entry in reader {
- let entry = entry
- .map_err(|_| ())?;
-
- let path = entry.path();
- let name = path.file_name().unwrap().to_string_lossy().into_owned();
-
- let child_route = route.extended_with(&[&name]);
-
- let child_item = self.read(&child_route)?;
-
- children.insert(name, child_item);
- }
-
- Ok(FileItem::Directory {
- children,
- route: route.clone(),
- })
- }
-}
diff --git a/server/src/web.rs b/server/src/web.rs
index 2a5fefd4..5d312aa4 100644
--- a/server/src/web.rs
+++ b/server/src/web.rs
@@ -1,197 +1,152 @@
-use std::borrow::Cow;
-use std::collections::HashMap;
-use std::sync::{mpsc, RwLock, Arc};
+use std::{
+ borrow::Cow,
+ collections::HashMap,
+ sync::{mpsc, Arc},
+};
use rouille::{self, Request, Response};
-use id::Id;
-use message_session::{MessageSession, Message};
-use project::Project;
-use rbx::RbxInstance;
-use rbx_session::RbxSession;
-use session::Session;
-
-/// The set of configuration the web server needs to start.
-pub struct WebConfig {
- pub port: u64,
- pub project: Project,
- pub server_id: u64,
- pub rbx_session: Arc>,
- pub message_session: MessageSession,
-}
-
-impl WebConfig {
- pub fn from_session(server_id: u64, port: u64, session: &Session) -> WebConfig {
- WebConfig {
- port,
- server_id,
- project: session.project.clone(),
- rbx_session: session.get_rbx_session(),
- message_session: session.get_message_session(),
- }
- }
-}
+use ::{
+ id::Id,
+ message_queue::Message,
+ project::Project,
+ rbx::RbxInstance,
+ session::Session,
+};
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ServerInfoResponse<'a> {
- pub server_id: &'a str,
+ pub session_id: &'a str,
pub server_version: &'a str,
pub protocol_version: u64,
- pub partitions: HashMap>,
-}
-
-#[derive(Debug, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct ReadAllResponse<'a> {
- pub server_id: &'a str,
- pub message_cursor: i32,
- pub instances: Cow<'a, HashMap>,
- pub partition_instances: Cow<'a, HashMap>,
+ pub root_instance_id: Id,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReadResponse<'a> {
- pub server_id: &'a str,
- pub message_cursor: i32,
+ pub session_id: &'a str,
+ pub message_cursor: u32,
pub instances: HashMap>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SubscribeResponse<'a> {
- pub server_id: &'a str,
- pub message_cursor: i32,
+ pub session_id: &'a str,
+ pub message_cursor: u32,
pub messages: Cow<'a, [Message]>,
}
pub struct Server {
- config: WebConfig,
+ session: Arc,
server_version: &'static str,
- server_id: String,
}
impl Server {
- pub fn new(config: WebConfig) -> Server {
+ pub fn new(session: Arc) -> Server {
Server {
+ session: session,
server_version: env!("CARGO_PKG_VERSION"),
- server_id: config.server_id.to_string(),
- config,
}
}
+ #[allow(unreachable_code)]
pub fn handle_request(&self, request: &Request) -> Response {
router!(request,
(GET) (/) => {
- Response::text("Rojo up and running!")
+ Response::text("Rojo is up and running!")
},
(GET) (/api/rojo) => {
// Get a summary of information about the server.
- let mut partitions = HashMap::new();
-
- for partition in self.config.project.partitions.values() {
- partitions.insert(partition.name.clone(), partition.target.clone());
- }
+ let tree = self.session.tree.read().unwrap();
Response::json(&ServerInfoResponse {
server_version: self.server_version,
protocol_version: 2,
- server_id: &self.server_id,
- partitions: partitions,
+ session_id: &self.session.session_id,
+ root_instance_id: tree.root_instance_id,
})
},
- (GET) (/api/subscribe/{ cursor: i32 }) => {
+ (GET) (/api/subscribe/{ cursor: u32 }) => {
// Retrieve any messages past the given cursor index, and if
// there weren't any, subscribe to receive any new messages.
+ let message_queue = Arc::clone(&self.session.message_queue);
+
// Did the client miss any messages since the last subscribe?
{
- let messages = self.config.message_session.messages.read().unwrap();
+ let (new_cursor, new_messages) = message_queue.get_messages_since(cursor);
- if cursor > messages.len() as i32 {
+ if new_messages.len() > 0 {
return Response::json(&SubscribeResponse {
- server_id: &self.server_id,
+ session_id: &self.session.session_id,
messages: Cow::Borrowed(&[]),
- message_cursor: messages.len() as i32 - 1,
- });
- }
-
- if cursor < messages.len() as i32 - 1 {
- let new_messages = &messages[(cursor + 1) as usize..];
- let new_cursor = cursor + new_messages.len() as i32;
-
- return Response::json(&SubscribeResponse {
- server_id: &self.server_id,
- messages: Cow::Borrowed(new_messages),
message_cursor: new_cursor,
- });
+ })
}
}
let (tx, rx) = mpsc::channel();
- let sender_id = self.config.message_session.subscribe(tx);
+ let sender_id = message_queue.subscribe(tx);
match rx.recv() {
Ok(_) => (),
Err(_) => return Response::text("error!").with_status_code(500),
}
- self.config.message_session.unsubscribe(sender_id);
+ message_queue.unsubscribe(sender_id);
{
- let messages = self.config.message_session.messages.read().unwrap();
- let new_messages = &messages[(cursor + 1) as usize..];
- let new_cursor = cursor + new_messages.len() as i32;
+ let (new_cursor, new_messages) = message_queue.get_messages_since(cursor);
- Response::json(&SubscribeResponse {
- server_id: &self.server_id,
- messages: Cow::Borrowed(new_messages),
+ return Response::json(&SubscribeResponse {
+ session_id: &self.session.session_id,
+ messages: Cow::Owned(new_messages),
message_cursor: new_cursor,
})
}
},
- (GET) (/api/read_all) => {
- let rbx_session = self.config.rbx_session.read().unwrap();
-
- let message_cursor = self.config.message_session.get_message_cursor();
-
- Response::json(&ReadAllResponse {
- server_id: &self.server_id,
- message_cursor,
- instances: Cow::Borrowed(rbx_session.tree.get_all_instances()),
- partition_instances: Cow::Borrowed(&rbx_session.partition_instances),
- })
- },
-
(GET) (/api/read/{ id_list: String }) => {
- let requested_ids = id_list
+ let message_queue = Arc::clone(&self.session.message_queue);
+
+ let requested_ids: Result, _> = id_list
.split(",")
- .map(str::parse::)
- .collect::, _>>();
+ .map(str::parse)
+ .collect();
let requested_ids = match requested_ids {
- Ok(v) => v,
+ Ok(id) => id,
Err(_) => return rouille::Response::text("Malformed ID list").with_status_code(400),
};
- let rbx_session = self.config.rbx_session.read().unwrap();
+ let tree = self.session.tree.read().unwrap();
- let message_cursor = self.config.message_session.get_message_cursor();
+ let message_cursor = message_queue.get_message_cursor();
let mut instances = HashMap::new();
- for requested_id in &requested_ids {
- rbx_session.tree.get_instance_and_descendants(*requested_id, &mut instances);
+ for &requested_id in &requested_ids {
+ match tree.get_instance(requested_id) {
+ Some(instance) => {
+ instances.insert(instance.get_id(), Cow::Borrowed(instance));
+
+ for descendant in tree.iter_descendants(requested_id) {
+ instances.insert(descendant.get_id(), Cow::Borrowed(descendant));
+ }
+ },
+ None => {},
+ }
}
Response::json(&ReadResponse {
- server_id: &self.server_id,
+ session_id: &self.session.session_id,
message_cursor,
instances,
})
@@ -200,13 +155,10 @@ impl Server {
_ => Response::empty_404()
)
}
-}
-/// Start the Rojo web server, taking over the current thread.
-#[allow(unreachable_code)]
-pub fn start(config: WebConfig) {
- let address = format!("localhost:{}", config.port);
- let server = Server::new(config);
+ pub fn listen(self, port: u64) {
+ let address = format!("localhost:{}", port);
- rouille::start_server(address, move |request| server.handle_request(request));
-}
+ rouille::start_server(address, move |request| self.handle_request(request));
+ }
+}
\ No newline at end of file
diff --git a/server/src/web_util.rs b/server/src/web_util.rs
index 0c344e6c..a6aea450 100644
--- a/server/src/web_util.rs
+++ b/server/src/web_util.rs
@@ -40,4 +40,4 @@ where
{
let body = read_json_text(&request)?;
serde_json::from_str(&body).ok()?
-}
+}
\ No newline at end of file
diff --git a/server/tests/read_projects.rs b/server/tests/read_projects.rs
new file mode 100644
index 00000000..05a85759
--- /dev/null
+++ b/server/tests/read_projects.rs
@@ -0,0 +1,36 @@
+#[macro_use] extern crate lazy_static;
+
+extern crate librojo;
+
+use std::{
+ collections::HashMap,
+ path::{Path, PathBuf},
+};
+
+use librojo::{
+ project::Project,
+};
+
+lazy_static! {
+ static ref TEST_PROJECTS_ROOT: PathBuf = {
+ Path::new(env!("CARGO_MANIFEST_DIR")).join("../test-projects")
+ };
+}
+
+#[test]
+fn foo() {
+ let project_file_location = TEST_PROJECTS_ROOT.join("foo.json");
+ let project = Project::load_exact(&project_file_location).unwrap();
+
+ assert_eq!(project.name, "foo");
+ assert_eq!(project.tree.len(), 1);
+}
+
+#[test]
+fn empty() {
+ let project_file_location = TEST_PROJECTS_ROOT.join("empty/roblox-project.json");
+ let project = Project::load_exact(&project_file_location).unwrap();
+
+ assert_eq!(project.name, "empty");
+ assert_eq!(project.tree.len(), 0);
+}
\ No newline at end of file
diff --git a/server/tests/web.rs b/server/tests/web.rs
deleted file mode 100644
index c9ae6259..00000000
--- a/server/tests/web.rs
+++ /dev/null
@@ -1,483 +0,0 @@
-#[macro_use] extern crate lazy_static;
-
-extern crate rouille;
-extern crate serde_json;
-extern crate serde;
-extern crate tempfile;
-extern crate walkdir;
-
-extern crate librojo;
-
-mod test_util;
-use test_util::*;
-
-use std::borrow::Cow;
-use std::collections::HashMap;
-use std::fs::{File, remove_file};
-use std::io::Write;
-use std::path::PathBuf;
-
-use librojo::{
- session::Session,
- project::Project,
- web::{Server, WebConfig, ServerInfoResponse, ReadResponse, ReadAllResponse, SubscribeResponse},
- rbx::RbxValue,
-};
-
-lazy_static! {
- static ref TEST_PROJECTS_ROOT: PathBuf = {
- let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
- path.push("../test-projects");
- path
- };
-}
-
-#[test]
-fn empty() {
- let original_project_path = TEST_PROJECTS_ROOT.join("empty");
-
- let project_tempdir = tempfile::tempdir().unwrap();
- let project_path = project_tempdir.path();
-
- copy_recursive(&original_project_path, &project_path).unwrap();
-
- let project = Project::load(&project_path).unwrap();
- let mut session = Session::new(project.clone());
- session.start();
-
- let web_config = WebConfig::from_session(0, project.serve_port, &session);
- let server = Server::new(web_config);
-
- {
- let body = server.get_string("/api/rojo");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.protocol_version, 2);
- assert_eq!(response.partitions.len(), 0);
- }
-
- {
- let body = server.get_string("/api/read_all");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, -1);
- assert_eq!(response.instances.len(), 0);
- }
-
- {
- let body = server.get_string("/api/read/0");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, -1);
- assert_eq!(response.instances.len(), 0);
- }
-}
-
-#[test]
-fn one_partition() {
- let original_project_path = TEST_PROJECTS_ROOT.join("one-partition");
-
- let project_tempdir = tempfile::tempdir().unwrap();
- let project_path = project_tempdir.path();
-
- copy_recursive(&original_project_path, &project_path).unwrap();
-
- let project = Project::load(&project_path).unwrap();
- let mut session = Session::new(project.clone());
- session.start();
-
- let web_config = WebConfig::from_session(0, project.serve_port, &session);
- let server = Server::new(web_config);
-
- {
- let body = server.get_string("/api/rojo");
- let response = serde_json::from_str::(&body).unwrap();
-
- let mut partitions = HashMap::new();
- partitions.insert("lib".to_string(), vec!["ReplicatedStorage".to_string(), "OnePartition".to_string()]);
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.protocol_version, 2);
- assert_eq!(response.partitions, partitions);
- }
-
- let initial_body = server.get_string("/api/read_all");
- let initial_response = {
- let response = serde_json::from_str::(&initial_body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, -1);
- assert_eq!(response.instances.len(), 4);
-
- let partition_id = *response.partition_instances.get("lib").unwrap();
-
- let mut root_id = None;
- let mut module_id = None;
- let mut client_id = None;
- let mut server_id = None;
-
- for (id, instance) in response.instances.iter() {
- match (instance.name.as_str(), instance.class_name.as_str()) {
- // TOOD: Should partition roots (and other directories) be some
- // magical object instead of Folder?
- // TODO: Should this name actually equal the last part of the
- // partition's target?
- ("OnePartition", "Folder") => {
- assert!(root_id.is_none());
- root_id = Some(*id);
-
- assert_eq!(*id, partition_id);
-
- assert_eq!(instance.properties.len(), 0);
- assert_eq!(instance.parent, None);
- assert_eq!(instance.children.len(), 3);
-
- let single_body = server.get_string(&format!("/api/read/{}", id));
- let single_response = serde_json::from_str::(&single_body).unwrap();
-
- let single_instance = single_response.instances.get(id).unwrap();
-
- assert_eq!(single_instance, &Cow::Borrowed(instance));
- },
- ("a", "ModuleScript") => {
- assert!(module_id.is_none());
- module_id = Some(*id);
-
- let mut properties = HashMap::new();
- properties.insert("Source".to_string(), RbxValue::String { value: "-- a.lua".to_string() });
-
- assert_eq!(instance.properties, properties);
- assert_eq!(instance.parent, Some(partition_id));
- assert_eq!(instance.children.len(), 0);
-
- let single_body = server.get_string(&format!("/api/read/{}", id));
- let single_response = serde_json::from_str::(&single_body).unwrap();
-
- let single_instance = single_response.instances.get(id).unwrap();
-
- assert_eq!(single_instance, &Cow::Borrowed(instance));
- },
- ("b", "LocalScript") => {
- assert!(client_id.is_none());
- client_id = Some(*id);
-
- let mut properties = HashMap::new();
- properties.insert("Source".to_string(), RbxValue::String { value: "-- b.client.lua".to_string() });
-
- assert_eq!(instance.properties, properties);
- assert_eq!(instance.parent, Some(partition_id));
- assert_eq!(instance.children.len(), 0);
-
- let single_body = server.get_string(&format!("/api/read/{}", id));
- let single_response = serde_json::from_str::(&single_body).unwrap();
-
- let single_instance = single_response.instances.get(id).unwrap();
-
- assert_eq!(single_instance, &Cow::Borrowed(instance));
- },
- ("a", "Script") => {
- assert!(server_id.is_none());
- server_id = Some(*id);
-
- let mut properties = HashMap::new();
- properties.insert("Source".to_string(), RbxValue::String { value: "-- a.server.lua".to_string() });
-
- assert_eq!(instance.properties, properties);
- assert_eq!(instance.parent, Some(partition_id));
- assert_eq!(instance.children.len(), 0);
-
- let single_body = server.get_string(&format!("/api/read/{}", id));
- let single_response = serde_json::from_str::(&single_body).unwrap();
-
- let single_instance = single_response.instances.get(id).unwrap();
-
- assert_eq!(single_instance, &Cow::Borrowed(instance));
- },
- _ => {
- panic!("Unexpected instance named {} of class {}", instance.name, instance.class_name);
- },
- }
- }
-
- let root_id = root_id.unwrap();
- let module_id = module_id.unwrap();
- let client_id = client_id.unwrap();
- let server_id = server_id.unwrap();
-
- {
- let root_instance = response.instances.get(&root_id).unwrap();
-
- assert!(root_instance.children.contains(&module_id));
- assert!(root_instance.children.contains(&client_id));
- assert!(root_instance.children.contains(&server_id));
- }
-
- response
- };
-
- {
- let temp_name = project_path.join("lib/c.client.lua");
-
- {
- let mut file = File::create(&temp_name).unwrap();
- file.write_all(b"-- c.client.lua").unwrap();
- }
-
- {
- // Block until Rojo detects the addition of our temp file
- let body = server.get_string("/api/subscribe/-1");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, 0);
- assert_eq!(response.messages.len(), 1);
-
- // TODO: Read which instance was changed and try to access it with
- // /read
- }
-
- let body = server.get_string("/api/read_all");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, 0);
- assert_eq!(response.instances.len(), 5);
-
- let partition_id = *response.partition_instances.get("lib").unwrap();
-
- let mut root_id = None;
- let mut module_id = None;
- let mut client_id = None;
- let mut server_id = None;
- let mut new_id = None;
-
- for (id, instance) in response.instances.iter() {
- match (instance.name.as_str(), instance.class_name.as_str()) {
- // TOOD: Should partition roots (and other directories) be some
- // magical object instead of Folder?
- // TODO: Should this name actually equal the last part of the
- // partition's target?
- ("OnePartition", "Folder") => {
- assert!(root_id.is_none());
- root_id = Some(*id);
-
- assert_eq!(*id, partition_id);
-
- assert_eq!(instance.properties.len(), 0);
- assert_eq!(instance.parent, None);
- assert_eq!(instance.children.len(), 4);
-
- let single_body = server.get_string(&format!("/api/read/{}", id));
- let single_response = serde_json::from_str::(&single_body).unwrap();
-
- let single_instance = single_response.instances.get(id).unwrap();
-
- assert_eq!(single_instance, &Cow::Borrowed(instance));
- },
- ("a", "ModuleScript") => {
- assert!(module_id.is_none());
- module_id = Some(*id);
-
- let mut properties = HashMap::new();
- properties.insert("Source".to_string(), RbxValue::String { value: "-- a.lua".to_string() });
-
- assert_eq!(instance.properties, properties);
- assert_eq!(instance.parent, Some(partition_id));
- assert_eq!(instance.children.len(), 0);
-
- let single_body = server.get_string(&format!("/api/read/{}", id));
- let single_response = serde_json::from_str::(&single_body).unwrap();
-
- let single_instance = single_response.instances.get(id).unwrap();
-
- assert_eq!(single_instance, &Cow::Borrowed(instance));
- },
- ("b", "LocalScript") => {
- assert!(client_id.is_none());
- client_id = Some(*id);
-
- let mut properties = HashMap::new();
- properties.insert("Source".to_string(), RbxValue::String { value: "-- b.client.lua".to_string() });
-
- assert_eq!(instance.properties, properties);
- assert_eq!(instance.parent, Some(partition_id));
- assert_eq!(instance.children.len(), 0);
-
- let single_body = server.get_string(&format!("/api/read/{}", id));
- let single_response = serde_json::from_str::(&single_body).unwrap();
-
- let single_instance = single_response.instances.get(id).unwrap();
-
- assert_eq!(single_instance, &Cow::Borrowed(instance));
- },
- ("a", "Script") => {
- assert!(server_id.is_none());
- server_id = Some(*id);
-
- let mut properties = HashMap::new();
- properties.insert("Source".to_string(), RbxValue::String { value: "-- a.server.lua".to_string() });
-
- assert_eq!(instance.properties, properties);
- assert_eq!(instance.parent, Some(partition_id));
- assert_eq!(instance.children.len(), 0);
-
- let single_body = server.get_string(&format!("/api/read/{}", id));
- let single_response = serde_json::from_str::(&single_body).unwrap();
-
- let single_instance = single_response.instances.get(id).unwrap();
-
- assert_eq!(single_instance, &Cow::Borrowed(instance));
- },
- ("c", "LocalScript") => {
- assert!(new_id.is_none());
- new_id = Some(*id);
-
- let mut properties = HashMap::new();
- properties.insert("Source".to_string(), RbxValue::String { value: "-- c.client.lua".to_string() });
-
- assert_eq!(instance.properties, properties);
- assert_eq!(instance.parent, Some(partition_id));
- assert_eq!(instance.children.len(), 0);
-
- let single_body = server.get_string(&format!("/api/read/{}", id));
- let single_response = serde_json::from_str::(&single_body).unwrap();
-
- let single_instance = single_response.instances.get(id).unwrap();
-
- assert_eq!(single_instance, &Cow::Borrowed(instance));
- },
- _ => {},
- }
- }
-
- let root_id = root_id.unwrap();
- let module_id = module_id.unwrap();
- let client_id = client_id.unwrap();
- let server_id = server_id.unwrap();
- let new_id = new_id.unwrap();
-
- let root_instance = response.instances.get(&root_id).unwrap();
-
- assert!(root_instance.children.contains(&module_id));
- assert!(root_instance.children.contains(&client_id));
- assert!(root_instance.children.contains(&server_id));
- assert!(root_instance.children.contains(&new_id));
-
- remove_file(&temp_name).unwrap();
- }
-
- {
- // Block until Rojo detects the removal of our temp file
- let body = server.get_string("/api/subscribe/0");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, 1);
- assert_eq!(response.messages.len(), 1);
- }
-
- {
- // Everything should be back to the initial state!
- let body = server.get_string("/api/read_all");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, 1);
- assert_eq!(response.instances.len(), 4);
-
- assert_eq!(response.instances, initial_response.instances);
- }
-
- // TODO: Test to change existing instance
-}
-
-#[test]
-fn partition_to_file() {
- let original_project_path = TEST_PROJECTS_ROOT.join("partition-to-file");
-
- let project_tempdir = tempfile::tempdir().unwrap();
- let project_path = project_tempdir.path();
-
- copy_recursive(&original_project_path, &project_path).unwrap();
-
- let project = Project::load(&project_path).unwrap();
- let mut session = Session::new(project.clone());
- session.start();
-
- let web_config = WebConfig::from_session(0, project.serve_port, &session);
- let server = Server::new(web_config);
-
- {
- let body = server.get_string("/api/rojo");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.protocol_version, 2);
- assert_eq!(response.partitions.len(), 1);
- }
-
- {
- let body = server.get_string("/api/read_all");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, -1);
- assert_eq!(response.instances.len(), 1);
-
- let (id, instance) = response.instances.iter().next().unwrap();
-
- assert_eq!(instance.name, "bar");
- assert_eq!(instance.class_name, "ModuleScript");
- assert_eq!(instance.properties.get("Source"), Some(&RbxValue::String { value: "-- foo.lua".to_string() }));
- assert_eq!(instance.children.len(), 0);
- assert_eq!(instance.parent, None);
-
- let body = server.get_string(&format!("/api/read/{}", id));
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, -1);
- assert_eq!(response.instances.len(), 1);
-
- let single_instance = response.instances.values().next().unwrap();
-
- assert_eq!(&Cow::Borrowed(instance), single_instance);
- }
-
- let file_path = project_path.join("foo.lua");
-
- {
- let mut file = File::create(file_path).unwrap();
- file.write_all(b"-- modified").unwrap();
- }
-
- {
- // Block until Rojo detects our file being modified
- let body = server.get_string("/api/subscribe/-1");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, 0);
- assert_eq!(response.messages.len(), 1);
- }
-
- {
- let body = server.get_string("/api/read/0");
- let response = serde_json::from_str::(&body).unwrap();
-
- assert_eq!(response.server_id, "0");
- assert_eq!(response.message_cursor, 0);
- assert_eq!(response.instances.len(), 1);
-
- let instance = response.instances.values().next().unwrap();
-
- assert_eq!(instance.name, "bar");
- assert_eq!(instance.class_name, "ModuleScript");
- assert_eq!(instance.properties.get("Source"), Some(&RbxValue::String { value: "-- modified".to_string() }));
- assert_eq!(instance.children.len(), 0);
- assert_eq!(instance.parent, None);
- }
-}
diff --git a/test-projects/empty/roblox-project.json b/test-projects/empty/roblox-project.json
new file mode 100644
index 00000000..5844e00e
--- /dev/null
+++ b/test-projects/empty/roblox-project.json
@@ -0,0 +1,4 @@
+{
+ "name": "empty",
+ "tree": {}
+}
\ No newline at end of file
diff --git a/test-projects/empty/rojo.json b/test-projects/empty/rojo.json
deleted file mode 100644
index 51c7917c..00000000
--- a/test-projects/empty/rojo.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "name": "empty",
- "servePort": 23456,
- "partitions": {}
-}
\ No newline at end of file
diff --git a/test-projects/foo.json b/test-projects/foo.json
new file mode 100644
index 00000000..f12be6a8
--- /dev/null
+++ b/test-projects/foo.json
@@ -0,0 +1,26 @@
+{
+ "name": "foo",
+ "tree": {
+ "ReplicatedStorage": {
+ "$className": "ReplicatedStorage",
+ "Rojo": {
+ "$className": "Folder",
+ "Plugin": {
+ "$path": "lib"
+ },
+ "Roact": {
+ "$path": "modules/roact/lib"
+ },
+ "Rodux": {
+ "$path": "modules/rodux/lib"
+ },
+ "RoactRodux": {
+ "$path": "modules/roact-rodux/lib"
+ },
+ "Promise": {
+ "$path": "modules/promise/lib"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test-projects/one-partition/lib/a.lua b/test-projects/one-partition/lib/a.lua
deleted file mode 100644
index f23fd06a..00000000
--- a/test-projects/one-partition/lib/a.lua
+++ /dev/null
@@ -1 +0,0 @@
--- a.lua
\ No newline at end of file
diff --git a/test-projects/one-partition/lib/a.server.lua b/test-projects/one-partition/lib/a.server.lua
deleted file mode 100644
index 08491e94..00000000
--- a/test-projects/one-partition/lib/a.server.lua
+++ /dev/null
@@ -1 +0,0 @@
--- a.server.lua
\ No newline at end of file
diff --git a/test-projects/one-partition/lib/b.client.lua b/test-projects/one-partition/lib/b.client.lua
deleted file mode 100644
index 12d034fa..00000000
--- a/test-projects/one-partition/lib/b.client.lua
+++ /dev/null
@@ -1 +0,0 @@
--- b.client.lua
\ No newline at end of file
diff --git a/test-projects/one-partition/rojo.json b/test-projects/one-partition/rojo.json
deleted file mode 100644
index d774a8f8..00000000
--- a/test-projects/one-partition/rojo.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "one-partition",
- "servePort": 23456,
- "partitions": {
- "lib": {
- "path": "lib",
- "target": "ReplicatedStorage.OnePartition"
- }
- }
-}
\ No newline at end of file
diff --git a/test-projects/partition-to-file/foo.lua b/test-projects/partition-to-file/foo.lua
deleted file mode 100644
index 4c3ac65c..00000000
--- a/test-projects/partition-to-file/foo.lua
+++ /dev/null
@@ -1 +0,0 @@
--- foo.lua
\ No newline at end of file
diff --git a/test-projects/partition-to-file/rojo.json b/test-projects/partition-to-file/rojo.json
deleted file mode 100644
index 0e7367f1..00000000
--- a/test-projects/partition-to-file/rojo.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "partition-to-file",
- "servePort": 23456,
- "partitions": {
- "lib": {
- "path": "foo.lua",
- "target": "ReplicatedStorage.bar"
- }
- }
-}
\ No newline at end of file
diff --git a/test-projects/single-sync-point/lib/main.lua b/test-projects/single-sync-point/lib/main.lua
new file mode 100644
index 00000000..e69de29b
diff --git a/test-projects/single-sync-point/roblox-project.json b/test-projects/single-sync-point/roblox-project.json
new file mode 100644
index 00000000..3681fb2b
--- /dev/null
+++ b/test-projects/single-sync-point/roblox-project.json
@@ -0,0 +1,11 @@
+{
+ "name": "empty",
+ "tree": {
+ "ReplicatedStorage": {
+ "$className": "ReplicatedStorage",
+ "Foo": {
+ "$path": "lib"
+ }
+ }
+ }
+}
\ No newline at end of file