Compare commits

...

15 Commits

Author SHA1 Message Date
Lucien Greathouse
273974b74f SmallString implementation 2022-05-27 02:54:33 -04:00
Lucien Greathouse
79b57b3359 Move memofs and rojo-insta-ext into crates folder 2022-05-26 04:23:44 -04:00
Lucien Greathouse
c7aeffe586 Switch from structopt to clap 2022-05-26 04:19:51 -04:00
Lucien Greathouse
79c02f2457 Delete old bin folder and update foreman.toml 2022-05-26 04:13:50 -04:00
Lucien Greathouse
b9ed68fa9e Release v7.1.1 2022-05-26 02:53:20 -04:00
Lucien Greathouse
6c6d6c9c8d Add .github/FUNDING.yml 2022-05-26 02:28:57 -04:00
Lucien Greathouse
e169d7be68 New release workflow (#547)
* Port release workflow from Aftman to test

* Checkout submodules in plugin build step

* ...and build with submodules for other builds too

* Fix ci.yml; we use master branch still

* CI with submodules too
2022-05-25 22:26:22 -04:00
Lucien Greathouse
192fd7d4dd New and improved CI pipeline 2022-05-25 18:53:08 -04:00
Lucien Greathouse
1f1193e857 Remove unused lazy_static 2022-05-25 18:48:57 -04:00
boatbomber
0a412ade88 Remove duplicate PluginSettings.StudioProvider (#545) 2022-05-25 18:48:10 -04:00
Filip Tibell
3cef2fe9aa Fix sourcemap command not stripping paths correctly (#544)
* Fix sourcemap command not stripping paths correctly

* Use ServeSession to get the proper root dir to strip for sourcemap
2022-05-23 15:19:30 -04:00
Lucien Greathouse
18e53f06fe Remove unused dependencies and dead code warnings 2022-05-22 19:20:41 -04:00
Lucien Greathouse
eaac539087 Update to reqwest 0.11.10 2022-05-22 19:16:43 -04:00
Lucien Greathouse
57005c4fd5 Update uuid and winreg 2022-05-22 19:13:11 -04:00
Lucien Greathouse
ea58999a2a Update to pretty_assertions 1.2.1 2022-05-22 19:12:33 -04:00
62 changed files with 713 additions and 1271 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1 @@
patreon: lpghatguy

View File

@@ -11,29 +11,49 @@ on:
jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
strategy:
matrix:
rust_version: [stable, "1.55.0"]
rust_version: [stable, 1.55.0]
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Rust toolchain
run: rustup default ${{ matrix.rust_version }}
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust_version }}
override: true
profile: minimal
- name: Build
run: cargo build --locked --verbose
- name: Run tests
- name: Test
run: cargo test --locked --verbose
- name: Rustfmt and Clippy
run: |
cargo fmt -- --check
cargo clippy
if: matrix.rust_version == 'stable'
lint:
name: Rustfmt and Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
components: rustfmt, clippy
- name: Rustfmt
run: cargo fmt -- --check
- name: Clippy
run: cargo clippy

View File

@@ -2,65 +2,152 @@ name: Release
on:
push:
tags: ["*"]
tags: ["v*"]
jobs:
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: Build release binary
run: cargo build --verbose --locked --release
- name: Upload artifacts
uses: actions/upload-artifact@v1
with:
name: rojo-win64
path: target/release/rojo.exe
macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: Install Rust
run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
- name: Build release binary
run: |
source $HOME/.cargo/env
cargo build --verbose --locked --release
env:
OPENSSL_STATIC: 1
- name: Upload artifacts
uses: actions/upload-artifact@v1
with:
name: rojo-macos
path: target/release/rojo
linux:
create-release:
name: Create Release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- uses: actions/checkout@v1
with:
submodules: true
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: true
prerelease: false
- name: Build
run: cargo build --locked --verbose --release
env:
OPENSSL_STATIC: 1
build-plugin:
needs: ["create-release"]
name: Build Roblox Studio Plugin
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Upload artifacts
uses: actions/upload-artifact@v1
with:
name: rojo-linux
path: target/release/rojo
- name: Setup Foreman
uses: Roblox/setup-foreman@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Build Plugin
run: rojo build plugin --output Rojo.rbxm
- name: Upload Plugin to Release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: Rojo.rbxm
asset_name: Rojo.rbxm
asset_content_type: application/octet-stream
- name: Upload Plugin to Artifacts
uses: actions/upload-artifact@v3
with:
name: Rojo.rbxm
path: Rojo.rbxm
build:
needs: ["create-release"]
strategy:
fail-fast: false
matrix:
# https://doc.rust-lang.org/rustc/platform-support.html
#
# FIXME: After the Rojo VS Code extension updates, add architecture
# names to each of these releases. We'll rename win64 to windows and add
# -x86_64 to each release.
include:
- host: linux
os: ubuntu-latest
target: x86_64-unknown-linux-gnu
label: linux
- host: windows
os: windows-latest
target: x86_64-pc-windows-msvc
label: win64
- host: macos
os: macos-latest
target: x86_64-apple-darwin
label: macos
- host: macos
os: macos-latest
target: aarch64-apple-darwin
label: macos-aarch64
name: Build (${{ matrix.target }})
runs-on: ${{ matrix.os }}
env:
BIN: rojo
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Get Version from Tag
shell: bash
# https://github.community/t/how-to-get-just-the-tag-name/16241/7#M1027
run: |
echo "PROJECT_VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
echo "Version is: ${{ env.PROJECT_VERSION }}"
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: ${{ matrix.target }}
override: true
profile: minimal
- name: Build Release
run: cargo build --release --locked --verbose
env:
# Build into a known directory so we can find our build artifact more
# easily.
CARGO_TARGET_DIR: output
# On platforms that use OpenSSL, ensure it is statically linked to
# make binaries more portable.
OPENSSL_STATIC: 1
- name: Create Release Archive
shell: bash
run: |
mkdir staging
if [ "${{ matrix.host }}" = "windows" ]; then
cp "output/release/$BIN.exe" staging/
cd staging
7z a ../release.zip *
else
cp "output/release/$BIN" staging/
cd staging
zip ../release.zip *
fi
- name: Upload Archive to Release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: release.zip
asset_name: ${{ env.BIN }}-${{ env.PROJECT_VERSION }}-${{ matrix.label }}.zip
asset_content_type: application/octet-stream
- name: Upload Archive to Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ env.BIN }}-${{ env.PROJECT_VERSION }}-${{ matrix.label }}.zip
path: release.zip

View File

@@ -1,6 +1,15 @@
# Rojo Changelog
## Unreleased Changes
* Switched from structopt to clap for command line argument parsing.
## [7.1.1] - May 26, 2022
* Fixed sourcemap command not stripping paths correctly ([#544])
* Fixed Studio plugin settings not saving correctly.
[#544]: https://github.com/rojo-rbx/rojo/pull/544
[#545]: https://github.com/rojo-rbx/rojo/pull/545
[7.1.1]: https://github.com/rojo-rbx/rojo/releases/tag/v7.1.1
## [7.1.0] - May 22, 2022
* Added support for specifying an address to be used by default in project files. ([#507])

View File

@@ -49,11 +49,9 @@ The Rojo release process is pretty manual right now. If you need to do it, here'
* `cargo publish`
8. Publish the Plugin
* `cargo run -- upload plugin --asset_id 6415005344`
* `cargo run -- build plugin --output Rojo.rbxm`
9. Push commits and tags
* `git push && git push --tags`
10. Copy GitHub release content from previous release
* Update the leading text with a summary about the release
* Paste the changelog notes (as-is!) from [`CHANGELOG.md`](CHANGELOG.md)
* Write a small summary of each major feature
* Attach release artifacts from GitHub Actions for each platform
* Write a small summary of each major feature

1086
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "rojo"
version = "7.1.0"
name = "rojo-smallstring"
version = "7.1.1"
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
description = "Enables professional-grade development tools for Roblox developers"
license = "MPL-2.0"
@@ -28,10 +28,7 @@ default = []
dev_live_assets = []
[workspace]
members = [
"rojo-insta-ext",
"memofs",
]
members = ["crates/*"]
[lib]
name = "librojo"
@@ -42,7 +39,7 @@ name = "build"
harness = false
[dependencies]
memofs = { version = "0.2.0", path = "memofs" }
memofs = { version = "0.2.0", path = "crates/memofs" }
# These dependencies can be uncommented when working on rbx-dom simultaneously
# rbx_binary = { path = "../rbx-dom/rbx_binary" }
@@ -69,29 +66,28 @@ globset = "0.4.8"
humantime = "2.1.0"
hyper = { version = "0.14.13", features = ["server", "tcp", "http1"] }
jod-thread = "0.1.2"
lazy_static = "1.4.0"
log = "0.4.14"
maplit = "1.0.2"
notify = "4.0.17"
opener = "0.5.0"
regex = "1.5.4"
reqwest = "0.9.24"
reqwest = { version = "0.11.10", features = ["blocking", "json"] }
ritz = "0.1.0"
rlua = "0.17.1"
roblox_install = "1.0.0"
serde = { version = "1.0.130", features = ["derive", "rc"] }
serde_json = "1.0.68"
structopt = "0.3.23"
termcolor = "1.1.2"
thiserror = "1.0.30"
tokio = { version = "1.12.0", features = ["rt", "rt-multi-thread"] }
uuid = { version = "0.8.2", features = ["v4", "serde"] }
uuid = { version = "1.0.0", features = ["v4", "serde"] }
clap = { version = "3.1.18", features = ["derive"] }
smol_str = "0.1.23"
profiling = { version = "1.0.6", features = ["profile-with-superluminal"] }
[target.'cfg(windows)'.dependencies]
winreg = "0.9.0"
winreg = "0.10.1"
[build-dependencies]
memofs = { version = "0.2.0", path = "memofs" }
memofs = { version = "0.2.0", path = "crates/memofs" }
embed-resource = "1.6.4"
anyhow = "1.0.44"
@@ -100,13 +96,12 @@ fs-err = "2.6.0"
maplit = "1.0.2"
[dev-dependencies]
rojo-insta-ext = { path = "rojo-insta-ext" }
rojo-insta-ext = { path = "crates/rojo-insta-ext" }
criterion = "0.3.5"
insta = { version = "1.8.0", features = ["redactions"] }
lazy_static = "1.4.0"
paste = "1.0.5"
pretty_assertions = "0.7.2"
pretty_assertions = "1.2.1"
serde_yaml = "0.8.21"
tempfile = "3.2.0"
walkdir = "2.3.2"

View File

@@ -1,5 +0,0 @@
#!/bin/sh
set -e
watchexec -c -w plugin "sh -c './bin/install-dev-plugin.sh'"

View File

@@ -1,13 +0,0 @@
#!/bin/sh
set -e
DIR="$( mktemp -d )"
PLUGIN_FILE="$DIR/Rojo.rbxm"
TESTEZ_FILE="$DIR/TestEZ.rbxm"
rojo build plugin -o "$PLUGIN_FILE"
rojo build plugin/testez.project.json -o "$TESTEZ_FILE"
remodel bin/mark-plugin-as-dev.lua "$PLUGIN_FILE" "$TESTEZ_FILE" 2>/dev/null
cp "$PLUGIN_FILE" "$LOCALAPPDATA/Roblox/Plugins/Rojo.rbxm"

View File

@@ -1,5 +0,0 @@
#!/bin/sh
set -e
rojo build plugin -o "$LOCALAPPDATA/Roblox/Plugins/Rojo.rbxm"

View File

@@ -1,12 +0,0 @@
local pluginPath, testezPath = ...
local plugin = remodel.readModelFile(pluginPath)[1]
local testez = remodel.readModelFile(testezPath)[1]
local marker = Instance.new("Folder")
marker.Name = "ROJO_DEV_BUILD"
marker.Parent = plugin
testez.Parent = plugin
remodel.writeModelFile(plugin, pluginPath)

View File

@@ -1,8 +0,0 @@
local pluginPath, placePath = ...
local plugin = remodel.readModelFile(pluginPath)[1]
local place = remodel.readPlaceFile(placePath)
plugin.Parent = place:GetService("ReplicatedStorage")
remodel.writePlaceFile(place, placePath)

View File

@@ -1,6 +0,0 @@
#!/bin/sh
set -e
./bin/run-cli-tests.sh
./bin/run-plugin-tests.sh

View File

@@ -1,9 +0,0 @@
#!/bin/sh
set -e
cargo test --all --locked
cargo fmt -- --check
touch src/lib.rs # Nudge Rust source to make Clippy actually check things
cargo clippy

View File

@@ -1,16 +0,0 @@
#!/bin/sh
set -e
DIR="$( mktemp -d )"
PLUGIN_FILE="$DIR/Rojo.rbxmx"
PLACE_FILE="$DIR/RojoTestPlace.rbxlx"
rojo build plugin -o "$PLUGIN_FILE"
rojo build plugin/place.project.json -o "$PLACE_FILE"
remodel bin/put-plugin-in-test-place.lua "$PLUGIN_FILE" "$PLACE_FILE"
run-in-roblox -s plugin/testBootstrap.server.lua "$PLACE_FILE"
luacheck plugin/src plugin/log plugin/http

View File

@@ -1,3 +1,4 @@
[tools]
rojo = { source = "rojo-rbx/rojo", version = "6.1.0" }
rojo = { source = "rojo-rbx/rojo", version = "7.1.1" }
run-in-roblox = { source = "rojo-rbx/run-in-roblox", version = "0.3.0" }
selene = { source = "Kampfkarren/selene", version = "0.17.0" }

View File

@@ -154,150 +154,146 @@ function App:render()
value = self.props.plugin,
}, {
e(Theme.StudioProvider, nil, {
e(PluginSettings.StudioProvider, {
plugin = self.props.plugin,
gui = e(StudioPluginGui, {
id = pluginName,
title = pluginName,
active = self.state.guiEnabled,
initDockState = Enum.InitialDockState.Right,
initEnabled = false,
overridePreviousState = false,
floatingSize = Vector2.new(300, 200),
minimumSize = Vector2.new(300, 200),
zIndexBehavior = Enum.ZIndexBehavior.Sibling,
onInitialState = function(initialState)
self:setState({
guiEnabled = initialState,
})
end,
onClose = function()
self:setState({
guiEnabled = false,
})
end,
}, {
gui = e(StudioPluginGui, {
id = pluginName,
title = pluginName,
active = self.state.guiEnabled,
NotConnectedPage = createPageElement(AppStatus.NotConnected, {
host = self.host,
onHostChange = self.setHost,
port = self.port,
onPortChange = self.setPort,
initDockState = Enum.InitialDockState.Right,
initEnabled = false,
overridePreviousState = false,
floatingSize = Vector2.new(300, 200),
minimumSize = Vector2.new(300, 200),
onConnect = function()
self:startSession()
end,
zIndexBehavior = Enum.ZIndexBehavior.Sibling,
onInitialState = function(initialState)
onNavigateSettings = function()
self:setState({
guiEnabled = initialState,
appStatus = AppStatus.Settings,
})
end,
}),
Connecting = createPageElement(AppStatus.Connecting),
Connected = createPageElement(AppStatus.Connected, {
projectName = self.state.projectName,
address = self.state.address,
onDisconnect = function()
self:endSession()
end,
}),
Settings = createPageElement(AppStatus.Settings, {
onBack = function()
self:setState({
appStatus = AppStatus.NotConnected,
})
end,
}),
Error = createPageElement(AppStatus.Error, {
errorMessage = self.state.errorMessage,
onClose = function()
self:setState({
guiEnabled = false,
appStatus = AppStatus.NotConnected,
toolbarIcon = Assets.Images.PluginButton,
})
end,
}, {
NotConnectedPage = createPageElement(AppStatus.NotConnected, {
host = self.host,
onHostChange = self.setHost,
port = self.port,
onPortChange = self.setPort,
onConnect = function()
self:startSession()
end,
onNavigateSettings = function()
self:setState({
appStatus = AppStatus.Settings,
})
end,
}),
Connecting = createPageElement(AppStatus.Connecting),
Connected = createPageElement(AppStatus.Connected, {
projectName = self.state.projectName,
address = self.state.address,
onDisconnect = function()
self:endSession()
end,
}),
Settings = createPageElement(AppStatus.Settings, {
onBack = function()
self:setState({
appStatus = AppStatus.NotConnected,
})
end,
}),
Error = createPageElement(AppStatus.Error, {
errorMessage = self.state.errorMessage,
onClose = function()
self:setState({
appStatus = AppStatus.NotConnected,
toolbarIcon = Assets.Images.PluginButton,
})
end,
}),
Background = Theme.with(function(theme)
return e("Frame", {
Size = UDim2.new(1, 0, 1, 0),
BackgroundColor3 = theme.BackgroundColor,
ZIndex = 0,
BorderSizePixel = 0,
})
end),
}),
toggleAction = e(StudioPluginAction, {
name = "RojoConnection",
title = "Rojo: Connect/Disconnect",
description = "Toggles the server for a Rojo sync session",
icon = Assets.Images.PluginButton,
bindable = true,
onTriggered = function()
if self.serveSession == nil or self.serveSession:getStatus() == ServeSession.Status.NotStarted then
self:startSession()
elseif self.serveSession ~= nil and self.serveSession:getStatus() == ServeSession.Status.Connected then
self:endSession()
end
end,
}),
connectAction = e(StudioPluginAction, {
name = "RojoConnect",
title = "Rojo: Connect",
description = "Connects the server for a Rojo sync session",
icon = Assets.Images.PluginButton,
bindable = true,
onTriggered = function()
if self.serveSession == nil or self.serveSession:getStatus() == ServeSession.Status.NotStarted then
self:startSession()
end
end,
}),
disconnectAction = e(StudioPluginAction, {
name = "RojoDisconnect",
title = "Rojo: Disconnect",
description = "Disconnects the server for a Rojo sync session",
icon = Assets.Images.PluginButton,
bindable = true,
onTriggered = function()
if self.serveSession ~= nil and self.serveSession:getStatus() == ServeSession.Status.Connected then
self:endSession()
end
end,
}),
toolbar = e(StudioToolbar, {
name = pluginName,
}, {
button = e(StudioToggleButton, {
name = "Rojo",
tooltip = "Show or hide the Rojo panel",
icon = self.state.toolbarIcon,
active = self.state.guiEnabled,
enabled = true,
onClick = function()
self:setState(function(state)
return {
guiEnabled = not state.guiEnabled,
}
end)
end,
Background = Theme.with(function(theme)
return e("Frame", {
Size = UDim2.new(1, 0, 1, 0),
BackgroundColor3 = theme.BackgroundColor,
ZIndex = 0,
BorderSizePixel = 0,
})
}),
end),
}),
toggleAction = e(StudioPluginAction, {
name = "RojoConnection",
title = "Rojo: Connect/Disconnect",
description = "Toggles the server for a Rojo sync session",
icon = Assets.Images.PluginButton,
bindable = true,
onTriggered = function()
if self.serveSession == nil or self.serveSession:getStatus() == ServeSession.Status.NotStarted then
self:startSession()
elseif self.serveSession ~= nil and self.serveSession:getStatus() == ServeSession.Status.Connected then
self:endSession()
end
end,
}),
connectAction = e(StudioPluginAction, {
name = "RojoConnect",
title = "Rojo: Connect",
description = "Connects the server for a Rojo sync session",
icon = Assets.Images.PluginButton,
bindable = true,
onTriggered = function()
if self.serveSession == nil or self.serveSession:getStatus() == ServeSession.Status.NotStarted then
self:startSession()
end
end,
}),
disconnectAction = e(StudioPluginAction, {
name = "RojoDisconnect",
title = "Rojo: Disconnect",
description = "Disconnects the server for a Rojo sync session",
icon = Assets.Images.PluginButton,
bindable = true,
onTriggered = function()
if self.serveSession ~= nil and self.serveSession:getStatus() == ServeSession.Status.Connected then
self:endSession()
end
end,
}),
toolbar = e(StudioToolbar, {
name = pluginName,
}, {
button = e(StudioToggleButton, {
name = "Rojo",
tooltip = "Show or hide the Rojo panel",
icon = self.state.toolbarIcon,
active = self.state.guiEnabled,
enabled = true,
onClick = function()
self:setState(function(state)
return {
guiEnabled = not state.guiEnabled,
}
end)
end,
})
}),
}),
})
@@ -314,4 +310,4 @@ return function(props)
return e(App, settingsProps)
end),
})
end
end

View File

@@ -5,7 +5,7 @@ local isDevBuild = script.Parent.Parent:FindFirstChild("ROJO_DEV_BUILD") ~= nil
return strict("Config", {
isDevBuild = isDevBuild,
codename = "Epiphany",
version = {7, 1, 0},
version = {7, 1, 1},
expectedServerVersionString = "7.0 or newer",
protocolVersion = 4,
defaultHost = "localhost",

View File

@@ -46,6 +46,7 @@ pub struct ChangeProcessor {
impl ChangeProcessor {
/// Spin up the ChangeProcessor, connecting it to the given tree, VFS, and
/// outbound message queue.
#[profiling::function]
pub fn start(
tree: Arc<Mutex<RojoTree>>,
vfs: Arc<Vfs>,

View File

@@ -4,9 +4,9 @@ use std::{
};
use anyhow::Context;
use clap::Parser;
use fs_err::File;
use memofs::Vfs;
use structopt::StructOpt;
use tokio::runtime::Runtime;
use crate::serve_session::ServeSession;
@@ -17,20 +17,20 @@ const UNKNOWN_OUTPUT_KIND_ERR: &str = "Could not detect what kind of file to bui
Expected output file to end in .rbxl, .rbxlx, .rbxm, or .rbxmx.";
/// Generates a model or place file from the Rojo project.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub struct BuildCommand {
/// Path to the project to serve. Defaults to the current directory.
#[structopt(default_value = "")]
#[clap(default_value = "")]
pub project: PathBuf,
/// Where to output the result.
///
/// Should end in .rbxm, .rbxl, .rbxmx, or .rbxlx.
#[structopt(long, short)]
#[clap(long, short)]
pub output: PathBuf,
/// Whether to automatically rebuild when any input files change.
#[structopt(long)]
#[clap(long)]
pub watch: bool,
}
@@ -97,6 +97,7 @@ fn xml_encode_config() -> rbx_xml::EncodeOptions {
rbx_xml::EncodeOptions::new().property_behavior(rbx_xml::EncodePropertyBehavior::WriteUnknown)
}
#[profiling::function]
fn write_model(
session: &ServeSession,
output: &Path,

View File

@@ -1,7 +1,7 @@
use structopt::StructOpt;
use clap::Parser;
/// Open Rojo's documentation in your browser.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub struct DocCommand {}
impl DocCommand {

View File

@@ -1,15 +1,15 @@
use std::path::PathBuf;
use anyhow::Context;
use structopt::StructOpt;
use clap::Parser;
use crate::project::Project;
/// Reformat a Rojo project using the standard JSON formatting rules.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub struct FmtProjectCommand {
/// Path to the project to format. Defaults to the current directory.
#[structopt(default_value = "")]
#[clap(default_value = "")]
pub project: PathBuf,
}

View File

@@ -4,9 +4,9 @@ use std::process::{Command, Stdio};
use std::str::FromStr;
use anyhow::{bail, format_err};
use clap::Parser;
use fs_err as fs;
use fs_err::OpenOptions;
use structopt::StructOpt;
use super::resolve_path;
@@ -22,14 +22,14 @@ static PLACE_README: &str = include_str!("../../assets/default-place-project/REA
static PLACE_GIT_IGNORE: &str = include_str!("../../assets/default-place-project/gitignore.txt");
/// Initializes a new Rojo project.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub struct InitCommand {
/// Path to the place to create the project. Defaults to the current directory.
#[structopt(default_value = "")]
#[clap(default_value = "")]
pub path: PathBuf,
/// The kind of project to create, 'place' or 'model'. Defaults to place.
#[structopt(long, default_value = "place")]
#[clap(long, default_value = "place")]
pub kind: InitKind,
}

View File

@@ -1,4 +1,4 @@
//! Defines Rojo's CLI through structopt types.
//! Defines Rojo's CLI through clap types.
mod build;
mod doc;
@@ -11,7 +11,7 @@ mod upload;
use std::{borrow::Cow, env, path::Path, str::FromStr};
use structopt::StructOpt;
use clap::Parser;
use thiserror::Error;
pub use self::build::BuildCommand;
@@ -23,15 +23,15 @@ pub use self::serve::ServeCommand;
pub use self::sourcemap::SourcemapCommand;
pub use self::upload::UploadCommand;
/// Command line options that Rojo accepts, defined using the structopt crate.
#[derive(Debug, StructOpt)]
#[structopt(name = "Rojo", about, author)]
/// Command line options that Rojo accepts, defined using the clap crate.
#[derive(Debug, Parser)]
#[clap(name = "Rojo", version, about, author)]
pub struct Options {
#[structopt(flatten)]
#[clap(flatten)]
pub global: GlobalOptions,
/// Subcommand to run in this invocation.
#[structopt(subcommand)]
#[clap(subcommand)]
pub subcommand: Subcommand,
}
@@ -50,14 +50,14 @@ impl Options {
}
}
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub struct GlobalOptions {
/// Sets verbosity level. Can be specified multiple times.
#[structopt(long("verbose"), short, global(true), parse(from_occurrences))]
#[clap(long("verbose"), short, global(true), parse(from_occurrences))]
pub verbosity: u8,
/// Set color behavior. Valid values are auto, always, and never.
#[structopt(long("color"), global(true), default_value("auto"))]
#[clap(long("color"), global(true), default_value("auto"))]
pub color: ColorChoice,
}
@@ -109,7 +109,7 @@ pub struct ColorChoiceParseError {
attempted: String,
}
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub enum Subcommand {
Init(InitCommand),
Serve(ServeCommand),

View File

@@ -3,9 +3,9 @@ use std::{
io::BufWriter,
};
use clap::Parser;
use memofs::{InMemoryFs, Vfs, VfsSnapshot};
use roblox_install::RobloxStudio;
use structopt::StructOpt;
use crate::serve_session::ServeSession;
@@ -13,14 +13,14 @@ static PLUGIN_BINCODE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/plugin.
static PLUGIN_FILE_NAME: &str = "RojoManagedPlugin.rbxm";
/// Install Rojo's plugin.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub struct PluginCommand {
#[structopt(subcommand)]
#[clap(subcommand)]
subcommand: PluginSubcommand,
}
/// Manages Rojo's Roblox Studio plugin.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub enum PluginSubcommand {
/// Install the plugin in Roblox Studio's plugins folder. If the plugin is
/// already installed, installing it again will overwrite the current plugin

View File

@@ -5,8 +5,8 @@ use std::{
sync::Arc,
};
use clap::Parser;
use memofs::Vfs;
use structopt::StructOpt;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
use crate::{serve_session::ServeSession, web::LiveServer};
@@ -17,19 +17,19 @@ const DEFAULT_BIND_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
const DEFAULT_PORT: u16 = 34872;
/// Expose a Rojo project to the Rojo Studio plugin.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub struct ServeCommand {
/// Path to the project to serve. Defaults to the current directory.
#[structopt(default_value = "")]
#[clap(default_value = "")]
pub project: PathBuf,
/// The IP address to listen on. Defaults to `127.0.0.1`.
#[structopt(long)]
#[clap(long)]
pub address: Option<IpAddr>,
/// The port to listen on. Defaults to the project's preference, or `34872` if
/// it has none.
#[structopt(long)]
#[clap(long)]
pub port: Option<u16>,
}

View File

@@ -3,11 +3,11 @@ use std::{
path::{Path, PathBuf},
};
use clap::Parser;
use fs_err::File;
use memofs::Vfs;
use rbx_dom_weak::types::Ref;
use serde::Serialize;
use structopt::StructOpt;
use crate::{
serve_session::ServeSession,
@@ -33,22 +33,22 @@ struct SourcemapNode {
}
/// Generates a sourcemap file from the Rojo project.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub struct SourcemapCommand {
/// Path to the project to use for the sourcemap. Defaults to the current
/// directory.
#[structopt(default_value = "")]
#[clap(default_value = "")]
pub project: PathBuf,
/// Where to output the sourcemap. Omit this to use stdout instead of
/// writing to a file.
///
/// Should end in .json.
#[structopt(long, short)]
#[clap(long, short)]
pub output: Option<PathBuf>,
/// If non-script files should be included or not. Defaults to false.
#[structopt(long)]
#[clap(long)]
pub include_non_scripts: bool,
}
@@ -56,9 +56,6 @@ impl SourcemapCommand {
pub fn run(self) -> anyhow::Result<()> {
let project_path = resolve_path(&self.project);
let mut project_dir = project_path.to_path_buf();
project_dir.pop();
log::trace!("Constructing in-memory filesystem");
let vfs = Vfs::new_default();
@@ -71,7 +68,7 @@ impl SourcemapCommand {
filter_non_scripts
};
let root_node = recurse_create_node(&tree, tree.get_root_id(), &project_dir, filter);
let root_node = recurse_create_node(&tree, tree.get_root_id(), session.root_dir(), filter);
if let Some(output_path) = self.output {
let mut file = BufWriter::new(File::create(&output_path)?);

View File

@@ -2,38 +2,38 @@ use std::path::PathBuf;
use std::str::FromStr;
use anyhow::{bail, format_err, Context};
use clap::Parser;
use memofs::Vfs;
use reqwest::{
header::{ACCEPT, CONTENT_TYPE, COOKIE, USER_AGENT},
StatusCode,
};
use structopt::StructOpt;
use crate::{auth_cookie::get_auth_cookie, serve_session::ServeSession};
use super::resolve_path;
/// Builds the project and uploads it to Roblox.
#[derive(Debug, StructOpt)]
#[derive(Debug, Parser)]
pub struct UploadCommand {
/// Path to the project to upload. Defaults to the current directory.
#[structopt(default_value = "")]
#[clap(default_value = "")]
pub project: PathBuf,
/// Authenication cookie to use. If not specified, Rojo will attempt to find one from the system automatically.
#[structopt(long)]
#[clap(long)]
pub cookie: Option<String>,
/// API key obtained from create.roblox.com/credentials. Rojo will use the Open Cloud API when this is provided. Only supports uploading to a place.
#[structopt(long = "api_key")]
#[clap(long = "api_key")]
pub api_key: Option<String>,
/// The Universe ID of the given place. Required when using the Open Cloud API.
#[structopt(long = "universe_id")]
#[clap(long = "universe_id")]
pub universe_id: Option<u64>,
/// Asset ID to upload to.
#[structopt(long = "asset_id")]
#[clap(long = "asset_id")]
pub asset_id: u64,
}
@@ -123,7 +123,7 @@ fn do_upload(buffer: Vec<u8>, asset_id: u64, cookie: &str) -> anyhow::Result<()>
asset_id
);
let client = reqwest::Client::new();
let client = reqwest::blocking::Client::new();
let build_request = move || {
client
@@ -172,10 +172,10 @@ fn do_upload_open_cloud(
universe_id, asset_id
);
let client = reqwest::Client::new();
let client = reqwest::blocking::Client::new();
log::debug!("Uploading to Roblox...");
let mut response = client
let response = client
.post(&url)
.header("x-api-key", api_key)
.header(CONTENT_TYPE, "application/xml")

View File

@@ -18,6 +18,7 @@ mod project;
mod resolution;
mod serve_session;
mod session_id;
mod small_string;
mod snapshot;
mod snapshot_middleware;
mod web;

View File

@@ -1,11 +1,13 @@
use std::{env, panic, process};
use backtrace::Backtrace;
use structopt::StructOpt;
use clap::Parser;
use librojo::cli::Options;
fn main() {
profiling::register_thread!("Main Thread");
panic::set_hook(Box::new(|panic_info| {
// PanicInfo's payload is usually a &'static str or String.
// See: https://doc.rust-lang.org/beta/std/panic/struct.PanicInfo.html#method.payload
@@ -49,7 +51,7 @@ fn main() {
process::exit(1);
}));
let options = Options::from_args();
let options = Options::parse();
let log_filter = match options.global.verbosity {
0 => "info",

View File

@@ -64,6 +64,7 @@ impl<T: Clone> MessageQueue<T> {
/// This method is only useful in tests. Non-test code should use subscribe
/// instead.
#[cfg(test)]
#[allow(unused)]
pub fn subscribe_any(&self) -> oneshot::Receiver<(u32, Vec<T>)> {
let cursor = {
let messages = self.messages.read().unwrap();

View File

@@ -36,17 +36,3 @@ where
seq.end()
}
pub fn serialize_option_absolute<S, T>(
maybe_path: &Option<T>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<Path>,
{
match maybe_path {
Some(path) => serialize_absolute(path, serializer),
None => serializer.serialize_none(),
}
}

View File

@@ -96,6 +96,7 @@ impl ServeSession {
/// The project file is expected to be loaded out-of-band since it's
/// currently loaded from the filesystem directly instead of through the
/// in-memory filesystem layer.
#[profiling::function]
pub fn new<P: AsRef<Path>>(vfs: Vfs, start_path: P) -> Result<Self, ServeSessionError> {
let start_path = start_path.as_ref();
let start_time = Instant::now();
@@ -216,6 +217,10 @@ impl ServeSession {
pub fn serve_address(&self) -> Option<IpAddr> {
self.root_project.serve_address
}
pub fn root_dir(&self) -> &Path {
self.root_project.folder_location()
}
}
#[derive(Debug, Error)]

1
src/small_string.rs Normal file
View File

@@ -0,0 +1 @@
pub use smol_str::SmolStr as SmallString;

View File

@@ -1,6 +1,6 @@
//! Defines the structure of an instance snapshot.
use std::{borrow::Cow, collections::HashMap};
use std::collections::HashMap;
use rbx_dom_weak::{
types::{Ref, Variant},
@@ -8,6 +8,8 @@ use rbx_dom_weak::{
};
use serde::{Deserialize, Serialize};
use crate::small_string::SmallString;
use super::InstanceMetadata;
/// A lightweight description of what an instance should look like.
@@ -25,13 +27,13 @@ pub struct InstanceSnapshot {
pub metadata: InstanceMetadata,
/// Correpsonds to the Name property of the instance.
pub name: Cow<'static, str>,
pub name: SmallString,
/// Corresponds to the ClassName property of the instance.
pub class_name: Cow<'static, str>,
pub class_name: SmallString,
/// All other properties of the instance, weakly-typed.
pub properties: HashMap<String, Variant>,
pub properties: HashMap<SmallString, Variant>,
/// The children of the instance represented as more snapshots.
///
@@ -44,37 +46,37 @@ impl InstanceSnapshot {
Self {
snapshot_id: None,
metadata: InstanceMetadata::default(),
name: Cow::Borrowed("DEFAULT"),
class_name: Cow::Borrowed("DEFAULT"),
name: "DEFAULT".into(),
class_name: "DEFAULT".into(),
properties: HashMap::new(),
children: Vec::new(),
}
}
pub fn name(self, name: impl Into<String>) -> Self {
pub fn name(self, name: impl Into<SmallString>) -> Self {
Self {
name: Cow::Owned(name.into()),
name: name.into(),
..self
}
}
pub fn class_name(self, class_name: impl Into<String>) -> Self {
pub fn class_name(self, class_name: impl Into<SmallString>) -> Self {
Self {
class_name: Cow::Owned(class_name.into()),
class_name: class_name.into(),
..self
}
}
pub fn property<K, V>(mut self, key: K, value: V) -> Self
where
K: Into<String>,
K: Into<SmallString>,
V: Into<Variant>,
{
self.properties.insert(key.into(), value.into());
self
}
pub fn properties(self, properties: impl Into<HashMap<String, Variant>>) -> Self {
pub fn properties(self, properties: impl Into<HashMap<SmallString, Variant>>) -> Self {
Self {
properties: properties.into(),
..self
@@ -112,12 +114,18 @@ impl InstanceSnapshot {
.map(|id| Self::from_tree(tree, id))
.collect();
let properties = instance
.properties
.iter()
.map(|(key, value)| (key.into(), value.clone()))
.collect();
Self {
snapshot_id: Some(id),
metadata: InstanceMetadata::default(),
name: Cow::Owned(instance.name.clone()),
class_name: Cow::Owned(instance.class.clone()),
properties: instance.properties.clone(),
name: SmallString::from(&instance.name),
class_name: SmallString::from(&instance.class),
properties,
children,
}
}

View File

@@ -5,6 +5,8 @@ use std::collections::HashMap;
use rbx_dom_weak::types::{Ref, Variant};
use serde::{Deserialize, Serialize};
use crate::small_string::SmallString;
use super::{InstanceMetadata, InstanceSnapshot};
/// A set of different kinds of patches that can be applied to an WeakDom.
@@ -40,12 +42,12 @@ pub struct PatchAdd {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PatchUpdate {
pub id: Ref,
pub changed_name: Option<String>,
pub changed_class_name: Option<String>,
pub changed_name: Option<SmallString>,
pub changed_class_name: Option<SmallString>,
/// Contains all changed properties. If a property is assigned to `None`,
/// then that property has been removed.
pub changed_properties: HashMap<String, Option<Variant>>,
pub changed_properties: HashMap<SmallString, Option<Variant>>,
/// Changed Rojo-specific metadata, if any of it changed.
pub changed_metadata: Option<InstanceMetadata>,
@@ -83,9 +85,9 @@ pub struct AppliedPatchUpdate {
pub id: Ref,
// TODO: Store previous values in order to detect application conflicts
pub changed_name: Option<String>,
pub changed_class_name: Option<String>,
pub changed_properties: HashMap<String, Option<Variant>>,
pub changed_name: Option<SmallString>,
pub changed_class_name: Option<SmallString>,
pub changed_properties: HashMap<SmallString, Option<Variant>>,
pub changed_metadata: Option<InstanceMetadata>,
}

View File

@@ -4,6 +4,8 @@ use std::collections::HashMap;
use rbx_dom_weak::types::{Ref, Variant};
use crate::small_string::SmallString;
use super::{
patch::{AppliedPatchSet, AppliedPatchUpdate, PatchSet, PatchUpdate},
InstanceSnapshot, RojoTree,
@@ -12,6 +14,7 @@ use super::{
/// Consumes the input `PatchSet`, applying all of its prescribed changes to the
/// tree and returns an `AppliedPatchSet`, which can be used to keep another
/// tree in sync with Rojo's.
#[profiling::function]
pub fn apply_patch_set(tree: &mut RojoTree, patch_set: PatchSet) -> AppliedPatchSet {
let mut context = PatchApplyContext::default();
@@ -68,7 +71,7 @@ struct PatchApplyContext {
///
/// This doesn't affect updated instances, since they're always applied
/// after we've added all the instances from the patch.
added_instance_properties: HashMap<Ref, HashMap<String, Variant>>,
added_instance_properties: HashMap<Ref, HashMap<SmallString, Variant>>,
/// The current applied patch result, describing changes made to the tree.
applied_patch_set: AppliedPatchSet,
@@ -100,7 +103,9 @@ fn finalize_patch_application(context: PatchApplyContext, tree: &mut RojoTree) -
}
}
instance.properties_mut().insert(key, property_value);
instance
.properties_mut()
.insert(key.to_string(), property_value);
}
}
@@ -164,13 +169,13 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
};
if let Some(name) = patch.changed_name {
*instance.name_mut() = name.clone();
applied_patch.changed_name = Some(name);
*instance.name_mut() = name.to_string();
applied_patch.changed_name = Some(name.into());
}
if let Some(class_name) = patch.changed_class_name {
*instance.class_name_mut() = class_name.clone();
applied_patch.changed_class_name = Some(class_name);
*instance.class_name_mut() = class_name.to_string();
applied_patch.changed_class_name = Some(class_name.into());
}
for (key, property_entry) in patch.changed_properties {
@@ -195,13 +200,15 @@ fn apply_update_child(context: &mut PatchApplyContext, tree: &mut RojoTree, patc
instance
.properties_mut()
.insert(key.clone(), Variant::Ref(new_referent));
.insert(key.to_string(), Variant::Ref(new_referent));
}
Some(ref value) => {
instance.properties_mut().insert(key.clone(), value.clone());
instance
.properties_mut()
.insert(key.to_string(), value.clone());
}
None => {
instance.properties_mut().remove(&key);
instance.properties_mut().remove(key.as_str());
}
}

View File

@@ -10,6 +10,7 @@ use super::{
InstanceSnapshot, InstanceWithMeta, RojoTree,
};
#[profiling::function]
pub fn compute_patch_set(
snapshot: Option<&InstanceSnapshot>,
tree: &RojoTree,
@@ -102,13 +103,13 @@ fn compute_property_patches(
let changed_name = if snapshot.name == instance.name() {
None
} else {
Some(snapshot.name.clone().into_owned())
Some(snapshot.name.clone())
};
let changed_class_name = if snapshot.class_name == instance.class_name() {
None
} else {
Some(snapshot.class_name.clone().into_owned())
Some(snapshot.class_name.clone())
};
let changed_metadata = if &snapshot.metadata == instance.metadata() {
@@ -120,7 +121,7 @@ fn compute_property_patches(
for (name, snapshot_value) in &snapshot.properties {
visited_properties.insert(name.as_str());
match instance.properties().get(name) {
match instance.properties().get(name.as_str()) {
Some(instance_value) => {
if snapshot_value != instance_value {
changed_properties.insert(name.clone(), Some(snapshot_value.clone()));
@@ -137,7 +138,7 @@ fn compute_property_patches(
continue;
}
changed_properties.insert(name.clone(), None);
changed_properties.insert(name.into(), None);
}
if changed_properties.is_empty()

View File

@@ -30,7 +30,7 @@ pub fn snapshot_csv(
.name(name)
.class_name("LocalizationTable")
.properties(hashmap! {
"Contents".to_owned() => table_contents.into(),
"Contents".into() => table_contents.into(),
})
.metadata(
InstanceMetadata::new()

View File

@@ -25,7 +25,7 @@ pub fn snapshot_json(
let as_lua = json_to_lua(value).to_string();
let properties = hashmap! {
"Source".to_owned() => as_lua.into(),
"Source".into() => as_lua.into(),
};
let meta_path = path.with_file_name(format!("{}.meta.json", name));

View File

@@ -1,4 +1,4 @@
use std::{borrow::Cow, collections::HashMap, path::Path, str};
use std::{collections::HashMap, path::Path, str};
use anyhow::Context;
use memofs::Vfs;
@@ -85,14 +85,14 @@ impl JsonModelCore {
let mut properties = HashMap::with_capacity(self.properties.len());
for (key, unresolved) in self.properties {
let value = unresolved.resolve(&class_name, &key)?;
properties.insert(key, value);
properties.insert(key.into(), value);
}
Ok(InstanceSnapshot {
snapshot_id: None,
metadata: Default::default(),
name: Cow::Owned(name),
class_name: Cow::Owned(class_name),
name: name.into(),
class_name: class_name.into(),
properties,
children,
})

View File

@@ -38,7 +38,7 @@ pub fn snapshot_lua(
.name(instance_name)
.class_name(class_name)
.properties(hashmap! {
"Source".to_owned() => contents_str.into(),
"Source".into() => contents_str.into(),
})
.metadata(
InstanceMetadata::new()

View File

@@ -1,4 +1,4 @@
use std::{borrow::Cow, collections::HashMap, path::PathBuf};
use std::{collections::HashMap, path::PathBuf};
use anyhow::{format_err, Context};
use serde::{Deserialize, Serialize};
@@ -49,7 +49,7 @@ impl AdjacentMetadata {
.resolve(&snapshot.class_name, &key)
.with_context(|| format!("error applying meta file {}", path.display()))?;
snapshot.properties.insert(key, value);
snapshot.properties.insert(key.into(), value);
}
Ok(())
@@ -116,7 +116,7 @@ impl DirectoryMetadata {
));
}
snapshot.class_name = Cow::Owned(class_name);
snapshot.class_name = class_name.into();
}
Ok(())
@@ -136,7 +136,7 @@ impl DirectoryMetadata {
.resolve(&snapshot.class_name, &key)
.with_context(|| format!("error applying meta file {}", path.display()))?;
snapshot.properties.insert(key, value);
snapshot.properties.insert(key.into(), value);
}
Ok(())

View File

@@ -40,6 +40,7 @@ pub use self::project::snapshot_project_node;
/// The main entrypoint to the snapshot function. This function can be pointed
/// at any path and will return something if Rojo knows how to deal with it.
#[profiling::function]
pub fn snapshot_from_vfs(
context: &InstanceContext,
vfs: &Vfs,

View File

@@ -6,6 +6,7 @@ use rbx_reflection::ClassTag;
use crate::{
project::{PathNode, Project, ProjectNode},
small_string::SmallString,
snapshot::{
InstanceContext, InstanceMetadata, InstanceSnapshot, InstigatingSource, PathIgnoreRule,
},
@@ -67,13 +68,10 @@ pub fn snapshot_project_node(
) -> anyhow::Result<Option<InstanceSnapshot>> {
let project_folder = project_path.parent().unwrap();
let class_name_from_project = node
.class_name
.as_ref()
.map(|name| Cow::Owned(name.clone()));
let class_name_from_project = node.class_name.as_ref().map(|name| SmallString::from(name));
let mut class_name_from_path = None;
let name = Cow::Owned(instance_name.to_owned());
let name = SmallString::from(instance_name);
let mut properties = HashMap::new();
let mut children = Vec::new();
let mut metadata = InstanceMetadata::default();
@@ -228,7 +226,7 @@ pub fn snapshot_project_node(
_ => {}
}
properties.insert(key.clone(), value);
properties.insert(key.into(), value);
}
// If the user specified $ignoreUnknownInstances, overwrite the existing
@@ -262,7 +260,7 @@ pub fn snapshot_project_node(
}))
}
fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<Cow<'static, str>> {
fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<SmallString> {
// If className wasn't defined from another source, we may be able
// to infer one.
@@ -275,13 +273,13 @@ fn infer_class_name(name: &str, parent_class: Option<&str>) -> Option<Cow<'stati
let descriptor = rbx_reflection_database::get().classes.get(name)?;
if descriptor.tags.contains(&ClassTag::Service) {
return Some(Cow::Owned(name.to_owned()));
return Some(name.into());
}
} else if parent_class == "StarterPlayer" {
// StarterPlayer has two special members with their own classes.
if name == "StarterPlayerScripts" || name == "StarterCharacterScripts" {
return Some(Cow::Owned(name.to_owned()));
return Some(name.into());
}
}

View File

@@ -21,7 +21,7 @@ pub fn snapshot_txt(
.to_owned();
let properties = hashmap! {
"Value".to_owned() => contents_str.into(),
"Value".into() => contents_str.into(),
};
let meta_path = path.with_file_name(format!("{}.meta.json", name));

View File

@@ -12,6 +12,7 @@ use serde::{Deserialize, Serialize};
use crate::{
session_id::SessionId,
small_string::SmallString,
snapshot::{
AppliedPatchSet, InstanceMetadata as RojoInstanceMetadata, InstanceWithMeta, RojoTree,
},
@@ -83,13 +84,13 @@ impl<'a> SubscribeMessage<'a> {
#[serde(rename_all = "camelCase")]
pub struct InstanceUpdate {
pub id: Ref,
pub changed_name: Option<String>,
pub changed_class_name: Option<String>,
pub changed_name: Option<SmallString>,
pub changed_class_name: Option<SmallString>,
// TODO: Transform from HashMap<String, Option<_>> to something else, since
// TODO: Transform from HashMap<_, Option<_>> to something else, since
// null will get lost when decoding from JSON in some languages.
#[serde(default)]
pub changed_properties: HashMap<String, Option<Variant>>,
pub changed_properties: HashMap<SmallString, Option<Variant>>,
pub changed_metadata: Option<InstanceMetadata>,
}

View File

@@ -141,14 +141,14 @@ impl TestServeSession {
pub fn get_api_rojo(&self) -> Result<ServerInfoResponse, reqwest::Error> {
let url = format!("http://localhost:{}/api/rojo", self.port);
let body = reqwest::get(&url)?.text()?;
let body = reqwest::blocking::get(&url)?.text()?;
Ok(serde_json::from_str(&body).expect("Server returned malformed response"))
}
pub fn get_api_read(&self, id: Ref) -> Result<ReadResponse, reqwest::Error> {
let url = format!("http://localhost:{}/api/read/{}", self.port, id);
let body = reqwest::get(&url)?.text()?;
let body = reqwest::blocking::get(&url)?.text()?;
Ok(serde_json::from_str(&body).expect("Server returned malformed response"))
}
@@ -159,7 +159,7 @@ impl TestServeSession {
) -> Result<SubscribeResponse<'static>, reqwest::Error> {
let url = format!("http://localhost:{}/api/subscribe/{}", self.port, cursor);
reqwest::get(&url)?.json()
reqwest::blocking::get(&url)?.json()
}
}