feat: add .gitignore for logs and refactor ServeSession to include path_roots in init_tree return

- Introduced a new .gitignore file to exclude log files from version control.
- Modified the `init_tree` function in `ServeSession` to return `path_roots`, enhancing the function's utility.
- Cleaned up commented-out code in `sourcemap.rs`, `patch_apply.rs`, and `tree.rs` for better readability and maintainability.
This commit is contained in:
Joe 2026-03-12 16:35:44 -05:00
parent 6325935557
commit 4ddc4a3e31
5 changed files with 36 additions and 74 deletions

1
.cursor/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/logs

View file

@ -88,8 +88,6 @@ impl SourcemapCommand {
filter_non_scripts filter_non_scripts
}; };
// Pre-build a rayon threadpool with a low number of threads to avoid
// dynamic creation overhead on systems with a high number of cpus.
rayon::ThreadPoolBuilder::new() rayon::ThreadPoolBuilder::new()
.num_threads(num_cpus::get().min(6)) .num_threads(num_cpus::get().min(6))
.build_global() .build_global()

View file

@ -17,7 +17,7 @@ use crate::{
session_id::SessionId, session_id::SessionId,
snapshot::{ snapshot::{
apply_patch_set, compute_patch_set, AppliedPatchSet, InstanceContext, InstanceSnapshot, apply_patch_set, compute_patch_set, AppliedPatchSet, InstanceContext, InstanceSnapshot,
PatchSet, PathIgnoreRule, RojoTree, PatchSet, RojoTree,
}, },
snapshot_middleware::{is_script_relevant_path, snapshot_from_vfs, INIT_FILE_PRIORITY}, snapshot_middleware::{is_script_relevant_path, snapshot_from_vfs, INIT_FILE_PRIORITY},
}; };
@ -330,7 +330,8 @@ impl ServeSession {
fn init_tree( fn init_tree(
vfs: &Vfs, vfs: &Vfs,
start_path: &Path, start_path: &Path,
) -> Result<(Project, RojoTree, Option<HashSet<PathBuf>>), ServeSessionError> { ) -> Result<(Project, RojoTree, Option<HashSet<PathBuf>>, Vec<PathBuf>), ServeSessionError>
{
log::trace!("Starting new ServeSession at path {}", start_path.display()); log::trace!("Starting new ServeSession at path {}", start_path.display());
let root_project = Project::load_initial_project(vfs, start_path)?; let root_project = Project::load_initial_project(vfs, start_path)?;
@ -421,69 +422,39 @@ impl ServeSession {
vfs.clear_prefetch_cache(); vfs.clear_prefetch_cache();
let patch_start = Instant::now(); let patch_start = Instant::now();
let watch_ignore_rules = root_project.path_ignore_rules();
std::thread::scope(|s| {
s.spawn(|| {
use walkdir::WalkDir;
let watch_start = Instant::now(); if vfs.is_watch_enabled() {
let mut watch_count: usize = 0; std::thread::scope(|s| {
s.spawn(|| {
if cfg!(target_os = "macos") { let watch_start = Instant::now();
// macOS kqueue: one FD per watched path. Walk each $path let mut watch_count: usize = 0;
// root, skip globIgnorePaths subtrees, and watch every
// non-ignored file and directory non-recursively. File
// watches are required because kqueue directory watches
// only fire for structural changes, not child content edits.
let passes_ignore = |entry: &walkdir::DirEntry| -> bool {
if let Some(name) = entry.file_name().to_str() {
if matches!(name, ".git" | ".hg" | ".svn") {
return false;
}
}
watch_ignore_rules
.iter()
.all(|rule: &PathIgnoreRule| rule.passes(entry.path()))
};
vfs.set_watch_recursive(false);
for root in &path_roots {
for entry in WalkDir::new(root)
.into_iter()
.filter_entry(&passes_ignore)
.flatten()
{
let _ = vfs.watch(entry.path());
watch_count += 1;
}
}
vfs.set_watch_recursive(true);
} else {
// Linux/Windows: inotify uses a single FD for all watches,
// RDCW uses one handle per directory. Recursive watches are
// cheap and directory watches already cover child file
// events. globIgnorePaths filtering is handled by the
// change processor's event filter.
for root in &path_roots { for root in &path_roots {
let _ = vfs.watch(root); let _ = vfs.watch(root);
watch_count += 1; watch_count += 1;
} }
} log::debug!(
log::debug!( "Set up {} watches in {:.1?}",
"Set up {} watches in {:.1?}", watch_count,
watch_count, watch_start.elapsed(),
watch_start.elapsed(), );
); });
});
log::trace!("Computing initial patch set");
let patch_set = compute_patch_set(snapshot, &tree, root_id);
log::trace!("Applying initial patch set");
apply_patch_set(&mut tree, patch_set);
});
} else {
log::trace!("Computing initial patch set"); log::trace!("Computing initial patch set");
let patch_set = compute_patch_set(snapshot, &tree, root_id); let patch_set = compute_patch_set(snapshot, &tree, root_id);
log::trace!("Applying initial patch set"); log::trace!("Applying initial patch set");
apply_patch_set(&mut tree, patch_set); apply_patch_set(&mut tree, patch_set);
}); }
log::debug!("Watch + patch in {:.1?}", patch_start.elapsed()); log::debug!("Watch + patch in {:.1?}", patch_start.elapsed());
Ok((root_project, tree, walked_paths)) Ok((root_project, tree, walked_paths, path_roots))
} }
/// Start a new serve session from the given in-memory filesystem and start /// Start a new serve session from the given in-memory filesystem and start
@ -500,7 +471,7 @@ impl ServeSession {
let start_path = start_path.as_ref(); let start_path = start_path.as_ref();
let start_time = Instant::now(); let start_time = Instant::now();
let (root_project, tree, _walked_paths) = Self::init_tree(&vfs, start_path)?; let (root_project, tree, _walked_paths, _path_roots) = Self::init_tree(&vfs, start_path)?;
let session_id = SessionId::new(); let session_id = SessionId::new();
let message_queue = MessageQueue::new(); let message_queue = MessageQueue::new();
@ -576,7 +547,7 @@ impl ServeSession {
let start_path = start_path.as_ref(); let start_path = start_path.as_ref();
let start_time = Instant::now(); let start_time = Instant::now();
let (root_project, tree, walked_paths) = Self::init_tree(&vfs, start_path)?; let (root_project, tree, walked_paths, _path_roots) = Self::init_tree(&vfs, start_path)?;
Ok(Self { Ok(Self {
change_processor: None, change_processor: None,

View file

@ -42,8 +42,6 @@ pub fn apply_patch_set(tree: &mut RojoTree, patch_set: PatchSet) -> AppliedPatch
{ {
profiling::scope!("updates"); profiling::scope!("updates");
// Updates need to be applied after additions, which reduces the complexity
// of updates significantly.
for update_patch in patch_set.updated_instances { for update_patch in patch_set.updated_instances {
apply_update_child(&mut context, tree, update_patch); apply_update_child(&mut context, tree, update_patch);
} }
@ -109,8 +107,6 @@ struct PatchApplyContext {
#[profiling::function] #[profiling::function]
fn finalize_patch_application(context: PatchApplyContext, tree: &mut RojoTree) -> AppliedPatchSet { fn finalize_patch_application(context: PatchApplyContext, tree: &mut RojoTree) -> AppliedPatchSet {
for id in context.has_refs_to_rewrite { for id in context.has_refs_to_rewrite {
// This should always succeed since instances marked as added in our
// patch should be added without fail.
let mut instance = tree let mut instance = tree
.get_instance_mut(id) .get_instance_mut(id)
.expect("Invalid instance ID in deferred property map"); .expect("Invalid instance ID in deferred property map");
@ -181,7 +177,6 @@ fn finalize_patch_application(context: PatchApplyContext, tree: &mut RojoTree) -
_ => continue, _ => continue,
}; };
// Remove all Rojo ref-related attributes
let keys_to_remove: Vec<String> = attributes let keys_to_remove: Vec<String> = attributes
.iter() .iter()
.filter_map(|(name, _)| { .filter_map(|(name, _)| {

View file

@ -125,28 +125,25 @@ impl RojoTree {
// //
// We need to insert the NeedsPivotMigration property with a value of false on // We need to insert the NeedsPivotMigration property with a value of false on
// every instance that inherits from Model for pivots to build correctly. // every instance that inherits from Model for pivots to build correctly.
let hack_needs_pivot_migration = match snapshot.class_name.as_ref() { let needs_pivot = match snapshot.class_name.as_ref() {
// This is not a future proof way to do this but the last time a
// descendant of Model was added was in 2020 so it's probably fine.
"Model" | "Actor" | "Tool" | "HopperBin" | "Flag" | "WorldModel" | "Workspace" "Model" | "Actor" | "Tool" | "HopperBin" | "Flag" | "WorldModel" | "Workspace"
| "Status" | "Status" => !snapshot
if !snapshot .properties
.properties .contains_key(&ustr("NeedsPivotMigration")),
.contains_key(&ustr("NeedsPivotMigration")) => _ => false,
{
vec![("NeedsPivotMigration", Variant::Bool(false))]
}
_ => Vec::new(),
}; };
let is_script = is_script_class(snapshot.class_name.as_ref()); let is_script = is_script_class(snapshot.class_name.as_ref());
let builder = InstanceBuilder::empty() let mut builder = InstanceBuilder::empty()
.with_class(snapshot.class_name) .with_class(snapshot.class_name)
.with_name(snapshot.name.into_owned()) .with_name(snapshot.name.into_owned())
.with_properties(hack_needs_pivot_migration)
.with_properties(snapshot.properties); .with_properties(snapshot.properties);
if needs_pivot {
builder = builder.with_property("NeedsPivotMigration", Variant::Bool(false));
}
let referent = self.inner.insert(parent_ref, builder); let referent = self.inner.insert(parent_ref, builder);
self.insert_metadata(referent, snapshot.metadata); self.insert_metadata(referent, snapshot.metadata);