Compare commits

...

26 Commits

Author SHA1 Message Date
Micah
c0a96e3811 Release v7.4.0 (#837) 2024-01-16 12:12:40 -08:00
Micah
9d0d76f0a5 Ensure plugin and Cargo version match exact at compile-time (#836) 2024-01-16 14:09:10 -06:00
Micah
c7173ac832 Don't serialize emitLegacyScripts if it's None (#835) 2024-01-16 10:09:16 -08:00
boatbomber
b12ce47e7e Don't remind to sync if the lock is claimed (#833)
If the sync lock is claimed in Team Create, the user cannot sync.
Therefore, a sync reminder notification is unhelpful as it is calling to
an invalid action.
2024-01-12 12:35:29 -08:00
Barış
269272983b Changed file extensions of init command from lua to luau (#831) 2024-01-05 16:00:49 -08:00
Kenneth Loeffler
6adc5eb9fb Conserve CI minutes via cache, skip macOS+Windows MSRV builds (#827)
Windows and macOS runners consume GitHub Actions minutes at [2x and 10x
the rate of Linux runners,
respectively](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#minute-multipliers).
This is a bit concerning now that there are two Windows jobs and two
macOS jobs, introduced in #825.

This PR aims to reduce the cost by:
* Adding [rust-cache](https://github.com/Swatinem/rust-cache/) to reduce
the amount of time spent. I'm aware there were some concerns raised
about CI caches in general in #496 - are they still a blocker?
* Removing the unnecessary Windows and macOS MSRV build jobs. If an MSRV
build fails on one platform due to usage of new language features, then
it will fail on all of them.

@Kampfkarren may have to change this repository's required status checks
before this PR can be merged
2024-01-02 15:49:24 -08:00
boatbomber
fd8bc8ae3f Improve visualization for arrays (#829) 2024-01-02 17:32:37 +00:00
Kenneth Loeffler
3369b0d429 Downgrade to Notify 4, use FSEvents, use minimal recursive watches (#830) 2024-01-02 09:26:06 -08:00
Kenneth Loeffler
097d39e8ce Fix move_folders_of_stuff (#826)
This is a fairly important test verifying whether the action of moving a
folder into a watched folder is correctly detected and processed. It was
disabled in
b43b45be8f.
The fact that it failed indicates a possible bug in change processing,
so in this PR, I'll re-enable the test, investigate why it fails, and
fix it.
2023-12-31 12:02:54 -08:00
Kenneth Loeffler
11fa08e6d6 Run CI workflow on Windows and macOS (#825)
This PR adds macOS and Windows jobs to the CI workflow. This allows us
to see when changes break functionality on any supported platform, which
is particularly important for changes that involve the file system or
file watcher.
2023-12-29 17:46:58 -08:00
Kenneth Loeffler
96987af71d Fix broken serve tests on macOS (#824)
Right now, serve tests will fail when Rojo is built with the FSEvent
backend. The cause is essentially due to the fact that `/var` (where
temporary directories for serve tests are located) on macOS is actually
a symlink to `/private/var`. Paths coming from FSEvent always have
symlinks expanded, but Rojo never expands symlinks. So, Rojo's paths
during these tests look like `/var/*` while the FSEvent paths look like
`/private/var/*`. When Rojo's change processor receives these events, it
considers them outside the project and does not apply any changes,
causing serve tests to time out.

To work around this, we can call `Path::canonicalize` before passing the
project path to `rojo serve` during serve tests. Rojo does need to
better support symlinks (which would also solve the problem), but I
think that can be left for another day because it's larger in scope and
I mostly just want working tests before addressing #609.
2023-12-28 23:17:00 +00:00
Vee
23327cb3ef Fix preloading assets in plugin (#819)
`gatherAssetUrlsRecursive` now returns asset URLs deeper than one layer.
2023-12-04 16:02:25 +00:00
Jack T
b43b45be8f Upgrade to Notify 6 (#816) 2023-11-23 16:16:43 -08:00
Micah
41994ec82e Release v7.4.0-rc3 (#811) 2023-10-25 17:01:06 -07:00
Micah
cd14ea7c62 Remove unnecessary borrows (#810) 2023-10-25 17:59:02 -05:00
Kenneth Loeffler
9f13bca6b8 rbx_dom_lua rojo-rbx/rbx-dom@440f3723 (attribute validation) (#809)
Brings over some changes to rbx_dom_lua to validate attribute names
before calling `Instance:SetAttribute`. This should prevent Rojo from
falling over when it attempts to sync an attribute with an invalid name.
2023-10-25 14:21:58 -07:00
Kenneth Loeffler
f4252c3e97 Update changelog in preparation for 7.4.0-rc3 (#808)
Summarizes recent changes since 7.4.0-rc2 in the changelog
2023-10-23 22:54:48 +00:00
Kenneth Loeffler
6598867d3d Bump rbx_binary to 0.7.3 (#807)
Bumps rbx_binary's version to 0.7.3 to bring in the missing
`SecurityCapabilities` serialization fallback default
2023-10-23 22:43:00 +00:00
dependabot[bot]
f39e040a0d Bump rustix from 0.38.15 to 0.38.20 (#806) 2023-10-23 22:38:28 +00:00
Kenneth Loeffler
a3d140269b Demote unapplied patch warnings to debug logs (#805)
These warnings always appear for properties like `Capabilities`,
`SourceAssetId`, etc. and tend to scare users who are syncing models.
This information is now surfaced in the patch visualizer, so I think
these warnings can be demoted to debug logs.
2023-10-23 11:47:50 -07:00
Kenneth Loeffler
feac29ea40 Fix PatchTree incorrect changeList entries on decode failure (#804) 2023-10-22 16:58:12 -07:00
Kenneth Loeffler
834c8cdbca rbx_dom_lua rojo-rbx/rbx-dom@0e10232b (SecurityCapabilities) (#803)
Closes #802.
2023-10-22 16:57:59 -07:00
Kenneth Loeffler
d441fbdf91 Bump rbx_dom_lua rojo-rbx/rbx-dom@e7a5b91c (ScriptEditorService) (#801) 2023-10-17 14:15:47 -07:00
Filip Tibell
e897f524dc Skip sourcemap generation when unaffected by changes in watch mode (#800) 2023-10-13 08:38:21 -07:00
Micah
1caf9446d8 Rojo 7.4.0-rc2 (#798) 2023-10-04 05:36:57 +00:00
Micah
bfd2c885db Properly handle build metadata in semver parsing in plugin (#797) 2023-10-04 05:23:18 +00:00
37 changed files with 1591 additions and 331 deletions

View File

@@ -23,4 +23,7 @@ insert_final_newline = true
insert_final_newline = true
[*.lua]
indent_style = tab
[*.luau]
indent_style = tab

View File

@@ -12,11 +12,11 @@ on:
jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
rust_version: [stable, 1.70.0]
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v3
@@ -26,10 +26,13 @@ jobs:
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.rust_version }}
toolchain: stable
override: true
profile: minimal
- name: Rust cache
uses: Swatinem/rust-cache@v2
- name: Setup Aftman
uses: ok-nick/setup-aftman@v0.3.0
with:
@@ -41,6 +44,33 @@ jobs:
- name: Test
run: cargo test --locked --verbose
msrv:
name: Check MSRV
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.70.0
override: true
profile: minimal
- name: Rust cache
uses: Swatinem/rust-cache@v2
- name: Setup Aftman
uses: ok-nick/setup-aftman@v0.3.0
with:
version: 'v0.2.7'
- name: Build
run: cargo build --locked --verbose
lint:
name: Rustfmt, Clippy, & Stylua
runs-on: ubuntu-latest
@@ -57,6 +87,9 @@ jobs:
override: true
components: rustfmt, clippy
- name: Rust cache
uses: Swatinem/rust-cache@v2
- name: Setup Aftman
uses: ok-nick/setup-aftman@v0.3.0
with:

View File

@@ -2,6 +2,37 @@
## Unreleased Changes
## [7.4.0] - January 16, 2024
* Improved the visualization for array properties like Tags ([#829])
* Significantly improved performance of `rojo serve`, `rojo build --watch`, and `rojo sourcemap --watch` on macOS. ([#830])
* Changed *.lua files that init command generates to *.luau ([#831])
* Does not remind users to sync if the sync lock is claimed already ([#833])
[#829]: https://github.com/rojo-rbx/rojo/pull/829
[#830]: https://github.com/rojo-rbx/rojo/pull/830
[#831]: https://github.com/rojo-rbx/rojo/pull/831
[#833]: https://github.com/rojo-rbx/rojo/pull/833
## [7.4.0-rc3] - October 25, 2023
* Changed `sourcemap --watch` to only generate the sourcemap when it's necessary ([#800])
* Switched script source property getter and setter to `ScriptEditorService` methods ([#801])
This ensures that the script editor reflects any changes Rojo makes to a script while it is open in the script editor.
* Fixed issues when handling `SecurityCapabilities` values ([#803], [#807])
* Fixed Rojo plugin erroring out when attempting to sync attributes with invalid names ([#809])
[#800]: https://github.com/rojo-rbx/rojo/pull/800
[#801]: https://github.com/rojo-rbx/rojo/pull/801
[#803]: https://github.com/rojo-rbx/rojo/pull/803
[#807]: https://github.com/rojo-rbx/rojo/pull/807
[#809]: https://github.com/rojo-rbx/rojo/pull/809
## [7.4.0-rc2] - October 3, 2023
* Fixed bug with parsing version for plugin validation ([#797])
[#797]: https://github.com/rojo-rbx/rojo/pull/797
## [7.4.0-rc1] - October 3, 2023
### Additions
#### Project format
@@ -118,7 +149,6 @@
* Add buttons for navigation on the Connected page ([#722])
### Fixes
* Significantly improved performance of `rojo serve` and `rojo build` on macOS. [#783]
* Significantly improved performance of `rojo sourcemap` ([#668])
* Fixed the diff visualizer of connected sessions. ([#674])
* Fixed disconnected session activity. ([#675])
@@ -152,7 +182,6 @@
[#770]: https://github.com/rojo-rbx/rojo/pull/770
[#771]: https://github.com/rojo-rbx/rojo/pull/771
[#774]: https://github.com/rojo-rbx/rojo/pull/774
[#783]: https://github.com/rojo-rbx/rojo/pull/783
[rbx-dom#299]: https://github.com/rojo-rbx/rbx-dom/pull/299
[rbx-dom#296]: https://github.com/rojo-rbx/rbx-dom/pull/296

31
Cargo.lock generated
View File

@@ -1586,9 +1586,9 @@ dependencies = [
[[package]]
name = "rbx_binary"
version = "0.7.2"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10942950a57c939e540a2f977ba55e9140007d7e96c532d455502c290fdf710d"
checksum = "6314dd6bf5c21d0598cdb53cf5d241aa643ba41da8b8abf7402b4a35096f03f6"
dependencies = [
"log",
"lz4",
@@ -1601,9 +1601,9 @@ dependencies = [
[[package]]
name = "rbx_dom_weak"
version = "2.6.0"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843a2e0e1446623625943f7228d9d4b5cf3883017e3964733600682506864b34"
checksum = "9b67b56bac99849c2e3c57547b036927f71c57cf7f4d900d04e3e4ee774ec316"
dependencies = [
"rbx_types",
"serde",
@@ -1611,9 +1611,9 @@ dependencies = [
[[package]]
name = "rbx_reflection"
version = "4.4.0"
version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41e762dfca3217d2d37da631de2fa0d1616edaa61a0a2633263d5d3305baf8c3"
checksum = "0d41509c991b53a7276a746a795eae2b9204f398164920f61976995b47fe1722"
dependencies = [
"rbx_types",
"serde",
@@ -1622,9 +1622,9 @@ dependencies = [
[[package]]
name = "rbx_reflection_database"
version = "0.2.9+roblox-596"
version = "0.2.10+roblox-607"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b18f088a2b4aa66324ec97b5b6ffacb53188aef19f3497d95d6a1d1dbb28e66"
checksum = "12e20c06fa41f7aadc79005c8354f592b2c2f4d0c61e1080ed5718dafc30aea0"
dependencies = [
"lazy_static",
"rbx_reflection",
@@ -1634,9 +1634,9 @@ dependencies = [
[[package]]
name = "rbx_types"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a991523e3ad5f43a4d121cb4a1e5bc23f7826bb4a1db5aa51e94f1073150ec"
checksum = "7ca23bfd469d067d81ef14f65fe09aeddc25abcf576a889d1a7664fe021cf18c"
dependencies = [
"base64 0.13.1",
"bitflags 1.3.2",
@@ -1649,9 +1649,9 @@ dependencies = [
[[package]]
name = "rbx_xml"
version = "0.13.2"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc87343301303ff0510903fb7eb3dbd1c75bdb6ab780fea6091bdc3f58b5829f"
checksum = "f8c03f95500961c32340791d1fabd4587f6873bdbff077ecca6ae32db7960dea"
dependencies = [
"base64 0.13.1",
"log",
@@ -1831,7 +1831,7 @@ dependencies = [
[[package]]
name = "rojo"
version = "7.4.0-rc1"
version = "7.4.0"
dependencies = [
"anyhow",
"backtrace",
@@ -1852,7 +1852,6 @@ dependencies = [
"log",
"maplit",
"memofs",
"notify",
"num_cpus",
"opener",
"paste",
@@ -1908,9 +1907,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.15"
version = "0.38.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2f9da0cbd88f9f09e7814e388301c8414c51c62aa6ce1e4b5c551d49d96e531"
checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0"
dependencies = [
"bitflags 2.4.0",
"errno",

View File

@@ -1,6 +1,6 @@
[package]
name = "rojo"
version = "7.4.0-rc1"
version = "7.4.0"
rust-version = "1.70.0"
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
description = "Enables professional-grade development tools for Roblox developers"
@@ -49,11 +49,11 @@ memofs = { version = "0.2.0", path = "crates/memofs" }
# rbx_reflection_database = { path = "../rbx-dom/rbx_reflection_database" }
# rbx_xml = { path = "../rbx-dom/rbx_xml" }
rbx_binary = "0.7.2"
rbx_dom_weak = "2.6.0"
rbx_reflection = "4.4.0"
rbx_reflection_database = "0.2.8"
rbx_xml = "0.13.2"
rbx_binary = "0.7.4"
rbx_dom_weak = "2.7.0"
rbx_reflection = "4.5.0"
rbx_reflection_database = "0.2.10"
rbx_xml = "0.13.3"
anyhow = "1.0.44"
backtrace = "0.3.61"
@@ -69,7 +69,6 @@ hyper = { version = "0.14.13", features = ["server", "tcp", "http1"] }
jod-thread = "0.1.2"
log = "0.4.14"
maplit = "1.0.2"
notify = "4.0.17"
num_cpus = "1.15.0"
opener = "0.5.0"
rayon = "1.7.0"

View File

@@ -46,14 +46,10 @@ fn main() -> Result<(), anyhow::Error> {
let our_version = Version::parse(env::var_os("CARGO_PKG_VERSION").unwrap().to_str().unwrap())?;
let plugin_version =
Version::parse(fs::read_to_string(&plugin_root.join("Version.txt"))?.trim())?;
Version::parse(fs::read_to_string(plugin_root.join("Version.txt"))?.trim())?;
assert!(
our_version.major == plugin_version.major,
"plugin version does not match Cargo version"
);
assert!(
our_version.minor == plugin_version.minor,
assert_eq!(
our_version, plugin_version,
"plugin version does not match Cargo version"
);

View File

@@ -1,7 +1,9 @@
# memofs Changelog
## Unreleased Changes
* Changed the `StdBackend` file watcher to use `PollWatcher` on macOS.
* Changed `StdBackend` file watching component to use minimal recursive watches. [#830]
[#830]: https://github.com/rojo-rbx/rojo/pull/830
## 0.2.0 (2021-08-23)
* Updated to `crossbeam-channel` 0.5.1.

View File

@@ -1,38 +1,24 @@
use std::io;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::{collections::HashSet, io};
use crossbeam_channel::Receiver;
use notify::{DebouncedEvent, RecursiveMode, Watcher};
#[cfg(target_os = "macos")]
use notify::PollWatcher;
#[cfg(not(target_os = "macos"))]
use notify::{watcher, RecommendedWatcher};
use notify::{watcher, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
use crate::{DirEntry, Metadata, ReadDir, VfsBackend, VfsEvent};
/// `VfsBackend` that uses `std::fs` and the `notify` crate.
pub struct StdBackend {
// We use PollWatcher on macos because using the KQueue watcher
// can cause some gnarly performance problems.
#[cfg(target_os = "macos")]
watcher: PollWatcher,
#[cfg(not(target_os = "macos"))]
watcher: RecommendedWatcher,
watcher_receiver: Receiver<VfsEvent>,
watches: HashSet<PathBuf>,
}
impl StdBackend {
pub fn new() -> StdBackend {
let (notify_tx, notify_rx) = mpsc::channel();
#[cfg(target_os = "macos")]
let watcher = PollWatcher::new(notify_tx, Duration::from_millis(50)).unwrap();
#[cfg(not(target_os = "macos"))]
let watcher = watcher(notify_tx, Duration::from_millis(50)).unwrap();
let (tx, rx) = crossbeam_channel::unbounded();
@@ -63,6 +49,7 @@ impl StdBackend {
Self {
watcher,
watcher_receiver: rx,
watches: HashSet::new(),
}
}
}
@@ -112,12 +99,22 @@ impl VfsBackend for StdBackend {
}
fn watch(&mut self, path: &Path) -> io::Result<()> {
self.watcher
.watch(path, RecursiveMode::NonRecursive)
.map_err(|inner| io::Error::new(io::ErrorKind::Other, inner))
if self.watches.contains(path)
|| path
.ancestors()
.any(|ancestor| self.watches.contains(ancestor))
{
Ok(())
} else {
self.watches.insert(path.to_path_buf());
self.watcher
.watch(path, RecursiveMode::Recursive)
.map_err(|inner| io::Error::new(io::ErrorKind::Other, inner))
}
}
fn unwatch(&mut self, path: &Path) -> io::Result<()> {
self.watches.remove(path);
self.watcher
.unwatch(path)
.map_err(|inner| io::Error::new(io::ErrorKind::Other, inner))

View File

@@ -1 +1 @@
7.4.0-rc1
7.4.0

View File

@@ -412,15 +412,6 @@ types = {
end,
},
SecurityCapabilities = {
fromPod = function(_pod)
error("SecurityCapabilities is not implemented")
end,
toPod = function(_roblox)
error("SecurityCapabilities is not implemented")
end,
},
SharedString = {
fromPod = function(_pod)
error("SharedString is not supported")

View File

@@ -1,4 +1,5 @@
local CollectionService = game:GetService("CollectionService")
local ScriptEditorService = game:GetService("ScriptEditorService")
--- A list of `Enum.Material` values that are used for Terrain.MaterialColors
local TERRAIN_MATERIAL_COLORS = {
@@ -36,9 +37,24 @@ return {
end,
write = function(instance, _, value)
local existing = instance:GetAttributes()
local didAllWritesSucceed = true
for key, attr in pairs(value) do
instance:SetAttribute(key, attr)
for attributeName, attributeValue in pairs(value) do
local isNameValid =
-- For our SetAttribute to succeed, the attribute name must be
-- less than or equal to 100 characters...
#attributeName <= 100
-- ...must only contain alphanumeric characters, periods, hyphens,
-- underscores, or forward slashes...
and attributeName:match("[^%w%.%-_/]") == nil
-- ... and must not use the RBX prefix, which is reserved by Roblox.
and attributeName:sub(1, 3) ~= "RBX"
if isNameValid then
instance:SetAttribute(attributeName, attributeValue)
else
didAllWritesSucceed = false
end
end
for key in pairs(existing) do
@@ -47,7 +63,7 @@ return {
end
end
return true
return didAllWritesSucceed
end,
},
Tags = {
@@ -116,4 +132,34 @@ return {
end,
},
},
Script = {
Source = {
read = function(instance: Script)
return true, ScriptEditorService:GetEditorSource(instance)
end,
write = function(instance: Script, _, value: string)
task.spawn(function()
ScriptEditorService:UpdateSourceAsync(instance, function()
return value
end)
end)
return true
end,
},
},
ModuleScript = {
Source = {
read = function(instance: ModuleScript)
return true, ScriptEditorService:GetEditorSource(instance)
end,
write = function(instance: ModuleScript, _, value: string)
task.spawn(function()
ScriptEditorService:UpdateSourceAsync(instance, function()
return value
end)
end)
return true
end,
},
},
}

File diff suppressed because it is too large Load Diff

View File

@@ -53,8 +53,23 @@ local function DisplayValue(props)
elseif next(props.value) == nil then
-- If it's empty, show empty braces
textRepresentation = "{}"
elseif next(props.value) == 1 then
-- We don't need to support mixed tables, so checking the first key is enough
-- to determine if it's a simple array
local out, i = table.create(#props.value), 0
for k, v in props.value do
i += 1
-- Wrap strings in quotes
if type(v) == "string" then
v = '"' .. v .. '"'
end
out[i] = tostring(v)
end
textRepresentation = "{ " .. table.concat(out, ", ") .. " }"
else
-- If it has children, list them out
-- Otherwise, show the table contents as a dictionary
local out, i = {}, 0
for k, v in pairs(props.value) do
i += 1

View File

@@ -136,6 +136,7 @@ function App:init()
and self.serveSession == nil
and Settings:get("syncReminder")
and self:getLastSyncTimestamp()
and (self:isSyncLockAvailable())
then
self:addNotification("You've previously synced this place. Would you like to reconnect?", 300, {
Connect = {
@@ -283,12 +284,39 @@ function App:getHostAndPort()
return host, port
end
function App:isSyncLockAvailable()
if #Players:GetPlayers() == 0 then
-- Team Create is not active, so no one can be holding the lock
return true
end
local lock = ServerStorage:FindFirstChild("__Rojo_SessionLock")
if not lock then
-- No lock is made yet, so it is available
return true
end
if lock.Value and lock.Value ~= Players.LocalPlayer and lock.Value.Parent then
-- Someone else is holding the lock
return false, lock.Value
end
-- The lock exists, but is not claimed
return true
end
function App:claimSyncLock()
if #Players:GetPlayers() == 0 then
Log.trace("Skipping sync lock because this isn't in Team Create")
return true
end
local isAvailable, priorOwner = self:isSyncLockAvailable()
if not isAvailable then
Log.trace("Skipping sync lock because it is already claimed")
return false, priorOwner
end
local lock = ServerStorage:FindFirstChild("__Rojo_SessionLock")
if not lock then
lock = Instance.new("ObjectValue")
@@ -300,11 +328,6 @@ function App:claimSyncLock()
return true
end
if lock.Value and lock.Value ~= Players.LocalPlayer and lock.Value.Parent then
Log.trace("Found existing sync lock owned by {}", lock.Value)
return false, lock.Value
end
lock.Value = Players.LocalPlayer
Log.trace("Claimed existing sync lock")
return true

View File

@@ -3,8 +3,9 @@ local strict = require(script.Parent.strict)
local isDevBuild = script.Parent.Parent:FindFirstChild("ROJO_DEV_BUILD") ~= nil
local Version = script.Parent.Parent.Version
local realVersion = Version.Value:split(".")
local major, minor, patch, metadata = Version.Value:match("^(%d+)%.(%d+)%.(%d+)(.*)$")
local realVersion = { major, minor, patch, metadata }
for i = 1, 3 do
local num = tonumber(realVersion[i])
if num then

View File

@@ -233,7 +233,7 @@ function PatchTree.build(patch, instanceMap, changeListHeaders)
addProp(
prop,
if currentSuccess then currentValue else "[Error]",
if incomingSuccess then incomingValue else next(incoming)
if incomingSuccess then incomingValue else select(2, next(incoming))
)
end
@@ -359,7 +359,7 @@ function PatchTree.build(patch, instanceMap, changeListHeaders)
if success then
table.insert(changeList, { prop, "N/A", incomingValue })
else
table.insert(changeList, { prop, "N/A", next(incoming) })
table.insert(changeList, { prop, "N/A", select(2, next(incoming)) })
end
end

View File

@@ -282,7 +282,7 @@ function ServeSession:__initialSync(serverInfo)
local unappliedPatch = self.__reconciler:applyPatch(catchUpPatch)
if not PatchSet.isEmpty(unappliedPatch) then
Log.warn(
Log.debug(
"Could not apply all changes requested by the Rojo server:\n{}",
PatchSet.humanSummary(self.__instanceMap, unappliedPatch)
)
@@ -309,7 +309,7 @@ function ServeSession:__mainSyncLoop()
local unappliedPatch = self.__reconciler:applyPatch(message)
if not PatchSet.isEmpty(unappliedPatch) then
Log.warn(
Log.debug(
"Could not apply all changes requested by the Rojo server:\n{}",
PatchSet.humanSummary(self.__instanceMap, unappliedPatch)
)

View File

@@ -13,7 +13,7 @@ function gatherAssetUrlsRecursive(currentTable, currentUrls)
if typeof(value) == "string" then
table.insert(currentUrls, value)
elseif typeof(value) == "table" then
gatherAssetUrlsRecursive(value)
gatherAssetUrlsRecursive(value, currentUrls)
end
end

View File

@@ -7,7 +7,7 @@ expression: contents
<Properties>
<string name="Name">server_init</string>
<token name="RunContext">0</token>
<string name="Source">return "From folder/init.server.lua"</string>
<string name="Source">return "From folder/init.server.luau"</string>
</Properties>
</Item>
</roblox>

View File

@@ -1 +0,0 @@
return "From folder/init.server.lua"

View File

@@ -0,0 +1 @@
return "From folder/init.server.luau"

View File

@@ -1,6 +1,5 @@
use std::{
fs,
path::PathBuf,
sync::{Arc, Mutex},
};
@@ -126,14 +125,41 @@ impl JobThreadContext {
// For a given VFS event, we might have many changes to different parts
// of the tree. Calculate and apply all of these changes.
let applied_patches = match event {
VfsEvent::Write(path) => {
if path.is_dir() {
return;
VfsEvent::Create(path) | VfsEvent::Remove(path) | VfsEvent::Write(path) => {
let mut tree = self.tree.lock().unwrap();
let mut applied_patches = Vec::new();
// Find the nearest ancestor to this path that has
// associated instances in the tree. This helps make sure
// that we handle additions correctly, especially if we
// receive events for descendants of a large tree being
// created all at once.
let mut current_path = path.as_path();
let affected_ids = loop {
let ids = tree.get_ids_at_path(&current_path);
log::trace!("Path {} affects IDs {:?}", current_path.display(), ids);
if !ids.is_empty() {
break ids.to_vec();
}
log::trace!("Trying parent path...");
match current_path.parent() {
Some(parent) => current_path = parent,
None => break Vec::new(),
}
};
for id in affected_ids {
if let Some(patch) = compute_and_apply_changes(&mut tree, &self.vfs, id) {
if !patch.is_empty() {
applied_patches.push(patch);
}
}
}
on_vfs_event(path, &self.tree, &self.vfs)
}
VfsEvent::Create(path) | VfsEvent::Remove(path) => {
on_vfs_event(path, &self.tree, &self.vfs)
applied_patches
}
_ => {
log::warn!("Unhandled VFS event: {:?}", event);
@@ -236,45 +262,6 @@ impl JobThreadContext {
}
}
// Find the nearest ancestor to this path that has
// associated instances in the tree. This helps make sure
// that we handle additions correctly, especially if we
// receive events for descendants of a large tree being
// created all at once.
fn on_vfs_event(
path: PathBuf,
tree: &Arc<Mutex<RojoTree>>,
vfs: &Arc<Vfs>,
) -> Vec<AppliedPatchSet> {
let mut tree = tree.lock().unwrap();
let mut applied_patches = Vec::new();
let mut current_path = path.as_path();
let affected_ids = loop {
let ids = tree.get_ids_at_path(current_path);
log::trace!("Path {} affects IDs {:?}", current_path.display(), ids);
if !ids.is_empty() {
break ids.to_vec();
}
log::trace!("Trying parent path...");
match current_path.parent() {
Some(parent) => current_path = parent,
None => break Vec::new(),
}
};
for id in affected_ids {
if let Some(patch) = compute_and_apply_changes(&mut tree, vfs, id) {
if !patch.is_empty() {
applied_patches.push(patch);
}
}
}
applied_patches
}
fn compute_and_apply_changes(tree: &mut RojoTree, vfs: &Vfs, id: Ref) -> Option<AppliedPatchSet> {
let metadata = tree
.get_metadata(id)

View File

@@ -146,7 +146,7 @@ impl OutputKind {
}
}
fn xml_encode_config() -> rbx_xml::EncodeOptions {
fn xml_encode_config() -> rbx_xml::EncodeOptions<'static> {
rbx_xml::EncodeOptions::new().property_behavior(rbx_xml::EncodePropertyBehavior::WriteUnknown)
}

View File

@@ -13,7 +13,7 @@ use super::resolve_path;
static MODEL_PROJECT: &str =
include_str!("../../assets/default-model-project/default.project.json");
static MODEL_README: &str = include_str!("../../assets/default-model-project/README.md");
static MODEL_INIT: &str = include_str!("../../assets/default-model-project/src-init.lua");
static MODEL_INIT: &str = include_str!("../../assets/default-model-project/src-init.luau");
static MODEL_GIT_IGNORE: &str = include_str!("../../assets/default-model-project/gitignore.txt");
static PLACE_PROJECT: &str =
@@ -116,17 +116,17 @@ fn init_place(base_path: &Path, project_params: ProjectParams) -> anyhow::Result
fs::create_dir_all(src.join(&src_client))?;
write_if_not_exists(
&src_shared.join("Hello.lua"),
&src_shared.join("Hello.luau"),
"return function()\n\tprint(\"Hello, world!\")\nend",
)?;
write_if_not_exists(
&src_server.join("init.server.lua"),
&src_server.join("init.server.luau"),
"print(\"Hello world, from server!\")",
)?;
write_if_not_exists(
&src_client.join("init.client.lua"),
&src_client.join("init.client.luau"),
"print(\"Hello world, from client!\")",
)?;
@@ -149,7 +149,7 @@ fn init_model(base_path: &Path, project_params: ProjectParams) -> anyhow::Result
fs::create_dir_all(&src)?;
let init = project_params.render_template(MODEL_INIT);
write_if_not_exists(&src.join("init.lua"), &init)?;
write_if_not_exists(&src.join("init.luau"), &init)?;
let git_ignore = project_params.render_template(MODEL_GIT_IGNORE);
try_git_init(base_path, &git_ignore)?;
@@ -170,7 +170,7 @@ fn init_plugin(base_path: &Path, project_params: ProjectParams) -> anyhow::Resul
fs::create_dir_all(&src)?;
write_if_not_exists(
&src.join("init.server.lua"),
&src.join("init.server.luau"),
"print(\"Hello world, from plugin!\")\n",
)?;

View File

@@ -14,7 +14,7 @@ use tokio::runtime::Runtime;
use crate::{
serve_session::ServeSession,
snapshot::{InstanceWithMeta, RojoTree},
snapshot::{AppliedPatchSet, InstanceWithMeta, RojoTree},
};
use super::resolve_path;
@@ -90,10 +90,12 @@ impl SourcemapCommand {
loop {
let receiver = session.message_queue().subscribe(cursor);
let (new_cursor, _patch_set) = rt.block_on(receiver).unwrap();
let (new_cursor, patch_set) = rt.block_on(receiver).unwrap();
cursor = new_cursor;
write_sourcemap(&session, self.output.as_deref(), filter)?;
if patch_set_affects_sourcemap(&session, &patch_set, filter) {
write_sourcemap(&session, self.output.as_deref(), filter)?;
}
}
}
@@ -116,6 +118,43 @@ fn filter_non_scripts(instance: &InstanceWithMeta) -> bool {
)
}
fn patch_set_affects_sourcemap(
session: &ServeSession,
patch_set: &[AppliedPatchSet],
filter: fn(&InstanceWithMeta) -> bool,
) -> bool {
let tree = session.tree();
// A sourcemap has probably changed when:
patch_set.par_iter().any(|set| {
// 1. An instance was removed, in which case it will no
// longer exist in the tree and we cant check the filter
!set.removed.is_empty()
// 2. A newly added instance passes the filter
|| set.added.iter().any(|referent| {
let instance = tree
.get_instance(*referent)
.expect("instance did not exist when updating sourcemap");
filter(&instance)
})
// 3. An existing instance has its class name, name,
// or file paths changed, and passes the filter
|| set.updated.iter().any(|updated| {
let changed = updated.changed_class_name.is_some()
|| updated.changed_name.is_some()
|| updated.changed_metadata.is_some();
if changed {
let instance = tree
.get_instance(updated.id)
.expect("instance did not exist when updating sourcemap");
filter(&instance)
} else {
false
}
})
})
}
fn recurse_create_node<'a>(
tree: &'a RojoTree,
referent: Ref,

View File

@@ -24,7 +24,7 @@ impl<K: Hash + Eq, V: Eq> MultiMap<K, V> {
K: Borrow<Q>,
Q: Hash + Eq,
{
self.inner.get(k.borrow()).map(Vec::as_slice).unwrap_or(&[])
self.inner.get(k).map(Vec::as_slice).unwrap_or(&[])
}
pub fn insert(&mut self, k: K, v: V) {

View File

@@ -8,9 +8,7 @@ use std::{
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::{
glob::Glob, resolution::UnresolvedValue, snapshot_middleware::emit_legacy_scripts_default,
};
use crate::{glob::Glob, resolution::UnresolvedValue};
static PROJECT_FILENAME: &str = "default.project.json";
@@ -75,12 +73,10 @@ pub struct Project {
#[serde(skip_serializing_if = "Option::is_none")]
pub serve_address: Option<IpAddr>,
/// Determines if rojo should emit scripts with the appropriate `RunContext` for `*.client.lua` and `*.server.lua` files in the project.
/// Or, if rojo should keep the legacy behavior of emitting LocalScripts and Scripts with legacy Runcontext
#[serde(
default = "emit_legacy_scripts_default",
skip_serializing_if = "Option::is_none"
)]
/// Determines if Rojo should emit scripts with the appropriate `RunContext`
/// for `*.client.lua` and `*.server.lua` files in the project instead of
/// using `Script` and `LocalScript` Instances.
#[serde(skip_serializing_if = "Option::is_none")]
pub emit_legacy_scripts: Option<bool>,
/// A list of globs, relative to the folder the project file is in, that

View File

@@ -159,7 +159,7 @@ impl ApiService {
})
.unwrap();
json_ok(&WriteResponse { session_id })
json_ok(WriteResponse { session_id })
}
async fn handle_api_read(&self, request: Request<Body>) -> Response<Body> {
@@ -271,7 +271,7 @@ impl ApiService {
},
};
json_ok(&OpenResponse {
json_ok(OpenResponse {
session_id: self.serve_session.session_id(),
})
}

View File

@@ -4,6 +4,6 @@
"$path": "src"
},
"plugins": [
"test-plugin.lua"
"test-plugin.luau"
]
}

View File

@@ -66,7 +66,11 @@ impl TestServeSession {
let source_path = Path::new(SERVE_TESTS_PATH).join(name);
let dir = tempdir().expect("Couldn't create temporary directory");
let project_path = dir.path().join(name);
let project_path = dir
.path()
.canonicalize()
.expect("Couldn't canonicalize temporary directory path")
.join(name);
let source_is_file = fs::metadata(&source_path).unwrap().is_file();