-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Description
I'm currently trying to write an exact file system watcher for a cargo project, so that any change that would cause a cargo build to actually end up recompiling the library can be detected. However, I'm stuck at figuring out just what file path changes to watch and react to:
- If I listen to all changes in
src, then I'll get false positives by temporary files or source files not part of the crate. - If I listen to all changes to
*.rsfiles insrc, I'll get false positves by source files not part of the crate, or false negatives for source files that don't have a*.rsending (the latter might be irrelevant in practice, but is still technical possible). - If I don't listen to anywhere outside
src, I miss changed or not yet downloaded dependencies - If I don't listen to anywhere outside
src, I miss changedrustcorcargoexecutables (say a new nightly).
So I need a way to ask cargo what paths to listen to, including:
- source of current package
- manifest of current package
rustcandcargoexecutables- path dependencies
Furthermore I need a high-performance way to actually ask cargo wether a change in any of those paths will cause a recompile. I could just shell out to cargo build each time any change is detected, but thats going to be wasteful if its just temporary files of an text editor or harmless other changes that won't trigger a recompilation.
If using cargo as a library already supports any of those usecases in a robust way, I've not been able to find it yet.
If its not currently possible to do these things with cargo I'd be willing to add the necessary library features, though I'd need guidance about how cargo is currently structured internally 😄 .
I have limited information about how this could be best implemented, but right now I'm thinking about an API like this:
struct FsWatchList {
paths: Vec<PathBuf>,
/// some state so that it can keep track of needing a rebuild without doing IO
needs_rebuild: bool,
}
impl FsWatchList {
/// Looks for a package in p and gathers the lists of filesystem paths
/// it could trigger a rebuild on.
fn new(p: &Path) -> Self { ... }
/// incorporate all the changed paths, and decide wether
/// they will cause a rebuild
fn merge_changes(&mut self, changed_paths: &[PathBuf]) { ... }
fn needs_rebuild(&self) -> bool { ... }
// ... accessors for the path list, etc
}
Using that API, a filesystem watcher could crawl the contents of a package once with FsWatchList::new(), setup a filesystem notifcator for all relevant paths, and then call merge_changes() and needs_rebuild() each time it receives an event, triggering an rebuild only if needed.
Ideally there would also be a trigger_rebuild() method that does the same as cargo build without shelling out at all, but thats a different issue.