watchexec/cargo-watch

Expose a list of modified files to shell commands

jyn514 opened this issue · 5 comments

I have a docker image where I mount my source directory in a volume, but run the build in a separate folder that I know is deterministic and doesn't interfere with the host target/ dir. Right now, I have a watch command that looks like this:

cargo watch -w /mnt/app -s 'cp -R /mnt/app/. /usr/src && cargo run'"

That works ok, but it copies over every file in the source directory, not just the ones that have been modified. Would you be interested in exposing the list of modified files to the command being run somehow? Maybe setting an environment variable?

That would allow me to do something like

cargo watch -w /mnt/app -s 'cp -R $MODIFIED_FILES /usr/src && cargo run'"

which has much better caching behavior.

This is supported in watchexec, though not in cargo watch. You can use watchexec directly for now, as a workaround.

The lesson from watchexec is that the env is terribly suited for this; it has a size limit and filenames quickly overwhelm it. I'm looking into alternatives before making it into cargo watch.

Another issue is that the file events may not actually cover everything that was changed, due to various annoying details of how file watching works (this is also platform-dependent). For the task of copying over only what's changed, you may be better served by e.g. https://github.com/kurtbuilds/checkexec and/or by a system like make which will look at the timestamps of the source and output files, or using find/fd.

Thanks! Those limitations make sense to me - I think it should be ok for my use case, since there's not many files and I don't need to worry special file types. I understand why you don't want to expose it in cargo-watch though :)

checkexec and make are not great choices because they aren't automatically rerun on changes and I don't want to use polling to avoid restarting the server more than I have to.

Oh, I meant to use those in combination with cargo watch / watchexec. Let the watcher provide the initial event, and the builder build up the list of what actually needs to happen.

ahhh, got it. I actually ended up just running cargo watch -s 'rsync -r -t /mnt/app/. /usr/src && cargo run', which preserves the timestamps so cargo doesn't recompile more than necessary :)

I'm going to add --experimental--env-changes as a hidden option to expose the WATCHEXEC_* environment variables if useful, until I put down a more permanent solution