Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing the model file triggers multiple rebuilds #29

Closed
hannobraun opened this issue Dec 28, 2021 · 12 comments
Closed

Changing the model file triggers multiple rebuilds #29

hannobraun opened this issue Dec 28, 2021 · 12 comments
Labels
type: bug Something isn't working

Comments

@hannobraun
Copy link
Owner

hannobraun commented Dec 28, 2021

Changing the model file while the host is running can trigger multiple rebuilds. I'm seeing two on Linux, and don't know about other platforms.

This is only a minor annoyance, so it's not critical to fix this. It would be nicer though if every change triggered exactly one rebuild, to save unnecessary work. This might be possibly by choosing the events we listen for more carefully, or maybe some kind of de-duplicating feature is required.

This problem has been introduced in #28.

@hannobraun hannobraun added type: bug Something isn't working topic: model labels Dec 28, 2021
@hannobraun
Copy link
Owner Author

hannobraun commented Dec 28, 2021

Adding the https://github.com/hannobraun/Fornjot/labels/good%20first%20issue label, since this is a fairly isolated problem that doesn't affect a lot of code. As of this writing, all the relevant code is located in main.rs. I think it would make sense to move it to model.rs though, but this doesn't need to be a part of this fix.

@hannobraun hannobraun added the good first issue Good for newcomers label Dec 28, 2021
@mxdamien
Copy link
Contributor

mxdamien commented Jan 17, 2022

The watcher is watching the complete 'mode/{model_name}/src' subfolder for changes. Events will be triggered for lib.rs but also for temporary and hidden files (e.g. Vim swap files during editing or intermediate compilation files). Would it make sense to restrict the watcher to just changes to model/{model_name}/src/lib.rs or only *.rs files?

@hannobraun
Copy link
Owner Author

Thank you, for the suggestions, @mxdamien!

I'm not sure what solution would be best. The intention is that a models can written in Rust, not just some restricted dialect. So watching just lib.rs would be too restrictive, as a non-trivial model could easily consist of multiple modules. Watching for all *.rs files would be better, but someone could include some non-Rust data file in their model (through something like include_str!/include_bytes!).

Maybe I'm being too paranoid about this last one, but I've experienced time and time again that software that's trying to be clever without being clever enough will become a huge frustration at some point.

How about this idea:

  • Watch all the Cargo files that could influence a build (Cargo.toml, Cargo.lock, build.rs, .cargo/config, .cargo/config.toml are the ones I can think of off the top of my head).
  • In addition, watch everything under src/.
  • Filter out events according to some built-in blacklist. That would include things like Vim swap files.

Would that work, or am I missing something? Maybe it would be better to leave out that first point, just watch everything and have a blacklist.

@mxdamien
Copy link
Contributor

mxdamien commented Jan 17, 2022

Watching everything under src/ and blacklisting file extensions has the desired effect. The rebuild/reload will only be triggered once.

mxdamien@c857ca7

But I'm not sure if this is really the best idea. The file watch event handling is OS dependent which makes the event filter a bit messy with the multiple different event types to react to. Maybe it would easier and safer to let the user trigger the reload manually e.g. by pressing R or CTRL+R ? This would also avoid accidentally triggering the rebuild of a model when saving an intermediate state of the model file.

@hannobraun
Copy link
Owner Author

hannobraun commented Jan 18, 2022

Thank you for looking into this!

But I'm not sure if this is really the best idea. The file watch event handling is OS dependent which makes the event filter a bit messy with the multiple different event types to react to. Maybe it would easier and safer to let the user trigger the reload manually e.g. by pressing R or CTRL+R ? This would also avoid accidentally triggering the rebuild of a model when saving an intermediate state of the model file.

I think manually reloading the model would be fine as a stop-gap solution, but long-term, it's not the user experience I would like. First, it's a manual step that you'd basically always want to take anyway, at least for the typical use case. Second, I plan to rely on an external editor/IDE indefinitely, so it would even be a two-step process (switch to Fornjot window, trigger reload).

It's true that the watch event handling code is a bit messy, but the commit you linked doesn't really seem to add to that. It just adds a check in a single place in the code. If you submitted that as a pull request, I'd be happy to merge that, mostly as-is.


In addition to figuring out the multiple rebuilds, I think it would be great to take the following measures:

  1. Clean up the platform-specific code. My idea is to have a platform module with a Platform trait (and one implementation per supported platform) that provides an API to platform-specific functionality (like a should_trigger_rebuild(&self, event: ...) -> bool method for this case). I've made a note and will open an issue once I find a bit of time. (edit: I've opened Hide platform-specific code behind a single API #36)
  2. Add an option to disable automatic rebuilds. Again, I've made a note and will open an issue soon-ish. (edit: I 've opened Add option to switch off automatic model reloading #37)

@hannobraun
Copy link
Owner Author

I've opened #36 and #37 as a follow-up to my previous comment here.

@mxdamien
Copy link
Contributor

mxdamien commented Jan 19, 2022

It's true that the watch event handling code is a bit messy, but the commit you linked doesn't really seem to add to that. It just adds a check in a single place in the code. If you submitted that as a pull request, I'd be happy to merge that, mostly as-is.

All right.
I played around with different file editors a bit more. I found that one editor I tried (VSCode) still triggers multiple rebuilds. It seems like it really modifies the file multiple times (notify::event::DataChange::Content triggers multiple times for lib.rs). The other editors I tried (vim, nano, gedit) now only trigger the rebuild once and only when the file is saved and not during editing.

I cleaned up the commit a bit and here is the PR:

#39

@hannobraun
Copy link
Owner Author

Thank you for looking into this, @mxdamien, I appreciate it!

I found that one editor I tried (VSCode) still triggers multiple rebuilds.

Interesting. I'm using VS Code, so that's probably what I've been seeing in the first place.

I'm wondering if we should even do anything about it. We could start tracking if something changed since the last rebuild, but that seems overkill, in addition to duplicating what Cargo already does. A more low-tech approach would be to delay the rebuild by some short time (50ms, or something along those lines) and ignore any events while a rebuild is scheduled anyway. That would have the disadvantage of adding to the compile time delay.

Probably best to just leave it for now and see if it turns into an actual problem.

@ObiWanRohan
Copy link
Contributor

I found that one editor I tried (VSCode) still triggers multiple rebuilds.

The 2 file changes with VS Code might be due to it saving the file first, and auto-formatting.

@hannobraun Are you using the rust-analyzer or the Rust extensions?

@hannobraun
Copy link
Owner Author

The 2 file changes with VS Code might be due to it saving the file first, and auto-formatting.

Makes sense. That could be it.

Are you using the rust-analyzer or the Rust extensions?

I'm using rust-analyzer. The "Rust" extension has been inferior to rust-analyzer for a long time now, and my understanding is that rust-analyzer is going to replace it as the official Rust extension.

@hannobraun
Copy link
Owner Author

Removing https://github.com/hannobraun/Fornjot/labels/good%20first%20issue label. It's not clear at all whether this is an issue that we can or should solve.

@hannobraun
Copy link
Owner Author

I've decided to close this. It's unclear whether we can or should do anything here.

If you run into a problem related to this, please comment here, or open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants