Compare commits

..

13 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
29 changed files with 1416 additions and 258 deletions

View File

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

View File

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

View File

@@ -2,6 +2,17 @@
## Unreleased Changes ## 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 ## [7.4.0-rc3] - October 25, 2023
* Changed `sourcemap --watch` to only generate the sourcemap when it's necessary ([#800]) * Changed `sourcemap --watch` to only generate the sourcemap when it's necessary ([#800])
* Switched script source property getter and setter to `ScriptEditorService` methods ([#801]) * Switched script source property getter and setter to `ScriptEditorService` methods ([#801])
@@ -138,7 +149,6 @@
* Add buttons for navigation on the Connected page ([#722]) * Add buttons for navigation on the Connected page ([#722])
### Fixes ### Fixes
* Significantly improved performance of `rojo serve` and `rojo build` on macOS. [#783]
* Significantly improved performance of `rojo sourcemap` ([#668]) * Significantly improved performance of `rojo sourcemap` ([#668])
* Fixed the diff visualizer of connected sessions. ([#674]) * Fixed the diff visualizer of connected sessions. ([#674])
* Fixed disconnected session activity. ([#675]) * Fixed disconnected session activity. ([#675])
@@ -172,7 +182,6 @@
[#770]: https://github.com/rojo-rbx/rojo/pull/770 [#770]: https://github.com/rojo-rbx/rojo/pull/770
[#771]: https://github.com/rojo-rbx/rojo/pull/771 [#771]: https://github.com/rojo-rbx/rojo/pull/771
[#774]: https://github.com/rojo-rbx/rojo/pull/774 [#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#299]: https://github.com/rojo-rbx/rbx-dom/pull/299
[rbx-dom#296]: https://github.com/rojo-rbx/rbx-dom/pull/296 [rbx-dom#296]: https://github.com/rojo-rbx/rbx-dom/pull/296

27
Cargo.lock generated
View File

@@ -1586,9 +1586,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_binary" name = "rbx_binary"
version = "0.7.3" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad50c13afe91296dad6508ea7e29f4b665fa56cb664ad01eaf8fdbd3da69d5e1" checksum = "6314dd6bf5c21d0598cdb53cf5d241aa643ba41da8b8abf7402b4a35096f03f6"
dependencies = [ dependencies = [
"log", "log",
"lz4", "lz4",
@@ -1601,9 +1601,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_dom_weak" name = "rbx_dom_weak"
version = "2.6.0" version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843a2e0e1446623625943f7228d9d4b5cf3883017e3964733600682506864b34" checksum = "9b67b56bac99849c2e3c57547b036927f71c57cf7f4d900d04e3e4ee774ec316"
dependencies = [ dependencies = [
"rbx_types", "rbx_types",
"serde", "serde",
@@ -1611,9 +1611,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_reflection" name = "rbx_reflection"
version = "4.4.0" version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41e762dfca3217d2d37da631de2fa0d1616edaa61a0a2633263d5d3305baf8c3" checksum = "0d41509c991b53a7276a746a795eae2b9204f398164920f61976995b47fe1722"
dependencies = [ dependencies = [
"rbx_types", "rbx_types",
"serde", "serde",
@@ -1622,9 +1622,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_reflection_database" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b18f088a2b4aa66324ec97b5b6ffacb53188aef19f3497d95d6a1d1dbb28e66" checksum = "12e20c06fa41f7aadc79005c8354f592b2c2f4d0c61e1080ed5718dafc30aea0"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"rbx_reflection", "rbx_reflection",
@@ -1634,9 +1634,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_types" name = "rbx_types"
version = "1.7.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a991523e3ad5f43a4d121cb4a1e5bc23f7826bb4a1db5aa51e94f1073150ec" checksum = "7ca23bfd469d067d81ef14f65fe09aeddc25abcf576a889d1a7664fe021cf18c"
dependencies = [ dependencies = [
"base64 0.13.1", "base64 0.13.1",
"bitflags 1.3.2", "bitflags 1.3.2",
@@ -1649,9 +1649,9 @@ dependencies = [
[[package]] [[package]]
name = "rbx_xml" name = "rbx_xml"
version = "0.13.2" version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc87343301303ff0510903fb7eb3dbd1c75bdb6ab780fea6091bdc3f58b5829f" checksum = "f8c03f95500961c32340791d1fabd4587f6873bdbff077ecca6ae32db7960dea"
dependencies = [ dependencies = [
"base64 0.13.1", "base64 0.13.1",
"log", "log",
@@ -1831,7 +1831,7 @@ dependencies = [
[[package]] [[package]]
name = "rojo" name = "rojo"
version = "7.4.0-rc3" version = "7.4.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"backtrace", "backtrace",
@@ -1852,7 +1852,6 @@ dependencies = [
"log", "log",
"maplit", "maplit",
"memofs", "memofs",
"notify",
"num_cpus", "num_cpus",
"opener", "opener",
"paste", "paste",

View File

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

View File

@@ -48,12 +48,8 @@ fn main() -> Result<(), anyhow::Error> {
let plugin_version = 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!( assert_eq!(
our_version.major == plugin_version.major, our_version, plugin_version,
"plugin version does not match Cargo version"
);
assert!(
our_version.minor == plugin_version.minor,
"plugin version does not match Cargo version" "plugin version does not match Cargo version"
); );

View File

@@ -1,7 +1,9 @@
# memofs Changelog # memofs Changelog
## Unreleased Changes ## 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) ## 0.2.0 (2021-08-23)
* Updated to `crossbeam-channel` 0.5.1. * Updated to `crossbeam-channel` 0.5.1.

View File

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

View File

@@ -1 +1 @@
7.4.0-rc3 7.4.0

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 elseif next(props.value) == nil then
-- If it's empty, show empty braces -- If it's empty, show empty braces
textRepresentation = "{}" 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 else
-- If it has children, list them out -- Otherwise, show the table contents as a dictionary
local out, i = {}, 0 local out, i = {}, 0
for k, v in pairs(props.value) do for k, v in pairs(props.value) do
i += 1 i += 1

View File

@@ -136,6 +136,7 @@ function App:init()
and self.serveSession == nil and self.serveSession == nil
and Settings:get("syncReminder") and Settings:get("syncReminder")
and self:getLastSyncTimestamp() and self:getLastSyncTimestamp()
and (self:isSyncLockAvailable())
then then
self:addNotification("You've previously synced this place. Would you like to reconnect?", 300, { self:addNotification("You've previously synced this place. Would you like to reconnect?", 300, {
Connect = { Connect = {
@@ -283,12 +284,39 @@ function App:getHostAndPort()
return host, port return host, port
end 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() function App:claimSyncLock()
if #Players:GetPlayers() == 0 then if #Players:GetPlayers() == 0 then
Log.trace("Skipping sync lock because this isn't in Team Create") Log.trace("Skipping sync lock because this isn't in Team Create")
return true return true
end 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") local lock = ServerStorage:FindFirstChild("__Rojo_SessionLock")
if not lock then if not lock then
lock = Instance.new("ObjectValue") lock = Instance.new("ObjectValue")
@@ -300,11 +328,6 @@ function App:claimSyncLock()
return true return true
end 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 lock.Value = Players.LocalPlayer
Log.trace("Claimed existing sync lock") Log.trace("Claimed existing sync lock")
return true return true

View File

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

View File

@@ -7,7 +7,7 @@ expression: contents
<Properties> <Properties>
<string name="Name">server_init</string> <string name="Name">server_init</string>
<token name="RunContext">0</token> <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> </Properties>
</Item> </Item>
</roblox> </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::{ use std::{
fs, fs,
path::PathBuf,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@@ -126,14 +125,41 @@ impl JobThreadContext {
// For a given VFS event, we might have many changes to different parts // For a given VFS event, we might have many changes to different parts
// of the tree. Calculate and apply all of these changes. // of the tree. Calculate and apply all of these changes.
let applied_patches = match event { let applied_patches = match event {
VfsEvent::Write(path) => { VfsEvent::Create(path) | VfsEvent::Remove(path) | VfsEvent::Write(path) => {
if path.is_dir() { let mut tree = self.tree.lock().unwrap();
return; 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)
} applied_patches
VfsEvent::Create(path) | VfsEvent::Remove(path) => {
on_vfs_event(path, &self.tree, &self.vfs)
} }
_ => { _ => {
log::warn!("Unhandled VFS event: {:?}", event); 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> { fn compute_and_apply_changes(tree: &mut RojoTree, vfs: &Vfs, id: Ref) -> Option<AppliedPatchSet> {
let metadata = tree let metadata = tree
.get_metadata(id) .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) rbx_xml::EncodeOptions::new().property_behavior(rbx_xml::EncodePropertyBehavior::WriteUnknown)
} }

View File

@@ -13,7 +13,7 @@ use super::resolve_path;
static MODEL_PROJECT: &str = static MODEL_PROJECT: &str =
include_str!("../../assets/default-model-project/default.project.json"); include_str!("../../assets/default-model-project/default.project.json");
static MODEL_README: &str = include_str!("../../assets/default-model-project/README.md"); 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 MODEL_GIT_IGNORE: &str = include_str!("../../assets/default-model-project/gitignore.txt");
static PLACE_PROJECT: &str = 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))?; fs::create_dir_all(src.join(&src_client))?;
write_if_not_exists( write_if_not_exists(
&src_shared.join("Hello.lua"), &src_shared.join("Hello.luau"),
"return function()\n\tprint(\"Hello, world!\")\nend", "return function()\n\tprint(\"Hello, world!\")\nend",
)?; )?;
write_if_not_exists( write_if_not_exists(
&src_server.join("init.server.lua"), &src_server.join("init.server.luau"),
"print(\"Hello world, from server!\")", "print(\"Hello world, from server!\")",
)?; )?;
write_if_not_exists( write_if_not_exists(
&src_client.join("init.client.lua"), &src_client.join("init.client.luau"),
"print(\"Hello world, from client!\")", "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)?; fs::create_dir_all(&src)?;
let init = project_params.render_template(MODEL_INIT); 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); let git_ignore = project_params.render_template(MODEL_GIT_IGNORE);
try_git_init(base_path, &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)?; fs::create_dir_all(&src)?;
write_if_not_exists( write_if_not_exists(
&src.join("init.server.lua"), &src.join("init.server.luau"),
"print(\"Hello world, from plugin!\")\n", "print(\"Hello world, from plugin!\")\n",
)?; )?;

View File

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

View File

@@ -4,6 +4,6 @@
"$path": "src" "$path": "src"
}, },
"plugins": [ "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 source_path = Path::new(SERVE_TESTS_PATH).join(name);
let dir = tempdir().expect("Couldn't create temporary directory"); 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(); let source_is_file = fs::metadata(&source_path).unwrap().is_file();