Skip to content

Need a way to ask cargo if the current package needs to be recompiled. #1989

@Kimundi

Description

@Kimundi

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 *.rs files in src, I'll get false positves by source files not part of the crate, or false negatives for source files that don't have a *.rs ending (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 changed rustc or cargo executables (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
  • rustc and cargo executables
  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-rebuild-detectionArea: rebuild detection and fingerprintingC-feature-requestCategory: proposal for a feature. Before PR, ping rust-lang/cargo if this is not `Feature accepted`Command-reportS-needs-designStatus: Needs someone to work further on the design for the feature or fix. NOT YET accepted.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions