Compare commits

...

1324 Commits
0.11.0 ... main

Author SHA1 Message Date
Félix Saparelli 9f1f2e9d04
chore: Release 2024-05-16 14:20:58 +12:00
Félix Saparelli 0e393c25cf
update changelog 2024-05-16 14:20:36 +12:00
Luca Barbato 2026c52abd
feat: Add git-describe support (#832) 2024-05-15 13:02:25 +00:00
Félix Saparelli 72f069a847
chore: Release 2024-04-30 20:41:43 +12:00
Adit 4affed6fff
fix(cli): recursive paths provided by user getting treated non-recursively (#828) 2024-04-30 07:10:28 +00:00
Félix Saparelli e0084e69f8
fix ci again 2024-04-28 19:14:21 +12:00
Félix Saparelli 592b712c95
chore: Release 2024-04-28 18:55:23 +12:00
Félix Saparelli c9a3b9df00
chore: Release 2024-04-28 18:53:42 +12:00
Félix Saparelli e63d37f601
chore: Release 2024-04-28 18:52:50 +12:00
Félix Saparelli 14e6294f5a
chore: Release 2024-04-28 18:51:48 +12:00
Félix Saparelli 234d606563
chore: Release 2024-04-28 18:50:18 +12:00
Félix Saparelli 77405c8ce1
chore: Release 2024-04-28 18:48:50 +12:00
Félix Saparelli 6c23afe839
feat: make it possible to watch non-recursively (#827)
Fixes #227
Fixes #174

docs(cli): be more precise in print-events advice to use `-v`
docs(cli): improve jaq error help
feat(cli): add `-W` for non-recursive watches
feat(cli): use non-blocking logging
feat(globset): hide `fmt::Debug` spew from ignore crate
feat(ignore-files): hide `fmt::Debug` spew from ignore crate
feat(lib): make it possible to watch non-recursively
fix(lib): inserting `WatchedPath`s directly should be possible
refactor(lib): move `WatchedPath` out of `fs` mod
2024-04-28 06:33:07 +00:00
dependabot[bot] ee3795d776
Bump softprops/action-gh-release from 2.0.3 to 2.0.4 (#823)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-28 18:19:34 +12:00
Félix Saparelli eff96c7324
feat(project-origins): add support for out-of-tree git repos (#826) 2024-04-28 14:26:07 +12:00
Félix Saparelli a4df258735
doc: fix --on-busy-update help text (#825) 2024-04-23 14:44:59 +12:00
Félix Saparelli d388a280f0
ci: more build improvements (for next time) 2024-04-21 02:11:37 +12:00
Félix Saparelli bb97f71c8c
gha: probably the most frustrating syntax in the world 2024-04-21 02:04:56 +12:00
Félix Saparelli 953fa89dd9
even better 2024-04-21 02:02:57 +12:00
Félix Saparelli 0ef87821f2
Run manpage and completions in release when we've already built in releases 2024-04-21 01:57:09 +12:00
Félix Saparelli 62af5dd868
Fix dist manifest 2024-04-21 01:52:11 +12:00
Félix Saparelli 4497aaf515
Fix release builder 2024-04-21 01:38:11 +12:00
Félix Saparelli a63864c5f2
chore: Release 2024-04-21 01:18:24 +12:00
Félix Saparelli ee815ba166
chore: Release 2024-04-21 01:06:46 +12:00
Félix Saparelli d6138b9961
chore: Release 2024-04-21 01:04:18 +12:00
Félix Saparelli f73d388d18
Changelogs for filterers 2024-04-21 01:03:58 +12:00
Félix Saparelli 86d6c7d448
Remove more PR machinery 2024-04-21 01:02:40 +12:00
Félix Saparelli d317540fd3
chore: Release 2024-04-21 01:00:28 +12:00
Félix Saparelli 9d91c51651
chore: Release 2024-04-21 00:56:27 +12:00
Félix Saparelli 96480cb588
chore: Release 2024-04-21 00:55:14 +12:00
Félix Saparelli fd5afb8b3a
Add --wrap-process (#822) 2024-04-20 12:39:28 +00:00
Félix Saparelli e1cef25d7f
Fix watchexec-events tests 2024-04-21 00:36:59 +12:00
Félix Saparelli 22b58a66ab
Remove tagged filterer 2024-04-21 00:32:01 +12:00
Félix Saparelli 1c47ffbe1a
Update release.toml config 2024-04-21 00:30:56 +12:00
Félix Saparelli 48ff7ec68b
Remove PR machinery 2024-04-21 00:28:06 +12:00
Félix Saparelli 4023bf7124
chore: Release 2024-04-21 00:21:04 +12:00
Félix Saparelli 8864811e79
Fix watchexec-events self-dependency 2024-04-21 00:19:11 +12:00
Félix Saparelli 7535e17661
Fix #809: clear screen before starting process, not on every event (#821) 2024-04-20 12:15:52 +00:00
Félix Saparelli 8ad12b1f65
chore: Release 2024-04-21 00:13:30 +12:00
Félix Saparelli dca13fed43
chore: Release 2024-04-21 00:12:21 +12:00
Félix Saparelli f81aed1260
Don't create a tmpfile until one is needed (#820) 2024-04-20 23:52:28 +12:00
Félix Saparelli ec316a7279
Breaking changes to CLI: various removals (#819) 2024-04-20 11:44:21 +00:00
Félix Saparelli e505a9ad05
Breaking changes for --on-busy-update (#818) 2024-04-20 11:15:25 +00:00
Félix Saparelli 317221584a
Breaking changes for --shell (#817) 2024-04-20 10:58:29 +00:00
Félix Saparelli af24252f21
Experimental filter programs (#571) 2024-04-20 10:06:53 +00:00
Félix Saparelli b72248a38c
Update deps (#816) 2024-04-20 05:45:50 +00:00
Chris West 11b98f776a
feat: under --clear reset, always reset at exit (#797) 2024-04-20 17:03:19 +12:00
dependabot[bot] 8c22d0cac7
Bump actions/download-artifact from 3 to 4 (#732)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-20 04:59:04 +00:00
dependabot[bot] 338999eb65
Bump softprops/action-gh-release from 1 to 2 (#799)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-20 16:58:33 +12:00
dependabot[bot] 538439f045
Bump mathieudutour/github-tag-action from 6.1 to 6.2 (#798)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-20 16:58:27 +12:00
Félix Saparelli 75b2c4b4ae
Adapt supervisor to process-wrap (#815) 2024-04-20 16:58:17 +12:00
dependabot[bot] a6e0b3f70a
Bump actions/cache from 3 to 4 (#772)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-20 16:42:55 +12:00
dependabot[bot] f538b74e81
Bump actions/upload-artifact from 3 to 4 (#733)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-20 16:42:08 +12:00
dependabot[bot] a50ce396cb
Bump mio from 0.8.10 to 0.8.11 (#796)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-06 13:01:52 +13:00
Félix Saparelli 1846c96b86
feat(cli): Add NO_COLOR support (#779) 2024-02-11 05:13:41 +00:00
dependabot[bot] 8b39279423
Bump h2 from 0.3.22 to 0.3.24 (#769)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-20 04:39:42 +00:00
Félix Saparelli 7f4fba02ef
Remove fish completion from rpm and deb packaging (#767) 2024-01-13 01:29:55 +00:00
github-actions[bot] d3949cc6e9
release: watchexec-cli v1.25.1 (#764)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2024-01-05 04:41:32 +00:00
github-actions[bot] 465ccfc597
release: watchexec-filterer-ignore v3.0.1 (#763)
Co-authored-by: github-actions <github-actions@github.com>
2024-01-05 15:48:04 +13:00
github-actions[bot] 6a2f637a60
release: ignore-files v2.1.0 (#762)
Co-authored-by: github-actions <github-actions@github.com>
2024-01-04 11:32:58 +00:00
Félix Saparelli 4f757de8df
Canonicalise paths for ignore discovery (#760) 2024-01-04 09:32:47 +00:00
Félix Saparelli 217f57f6a2
Update to async-priority-channel 0.2.0 (#761) 2024-01-04 22:13:08 +13:00
github-actions[bot] 682a9b4d21
release: watchexec-cli v1.25.0 (#754)
Co-authored-by: github-actions <github-actions@github.com>
2024-01-01 10:39:18 +00:00
github-actions[bot] 447b6fa963
release: watchexec-filterer-globset v3.0.0 (#752)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2024-01-01 09:10:43 +00:00
github-actions[bot] 3cbf277b2e
release: watchexec-filterer-tagged v2.0.0 (#753)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2024-01-01 09:09:24 +00:00
github-actions[bot] 48793008eb
release: watchexec-filterer-ignore v3.0.0 (#751)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2024-01-01 08:47:32 +00:00
github-actions[bot] 1ef2fcebf1
release: ignore-files v2.0.0 (#750)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2024-01-01 07:54:19 +00:00
github-actions[bot] 8523bd196c
release: project-origins v1.3.0 (#749)
Co-authored-by: github-actions <github-actions@github.com>
2024-01-01 06:07:03 +00:00
Victor Adossi ("vados") cb1cfb6bf5
Optimise ignore file gathering (#663)
Co-authored-by: Félix Saparelli <felix@passcod.name>
2024-01-01 05:01:14 +00:00
Félix Saparelli bf9c85f598
Tweak origin detection lists (#748) 2024-01-01 03:41:14 +00:00
thislooksfun 3ad0e1aa57
Respect `applies_in` scope when processing nested ignores (#746)
Previously, when importing multiple nested ignore files, some info from
the parent—notably the "root" path—would be inherited. This lead to some
problems with matching of "pseudo-absolute" rules (those with a leading
slash) in nested ignore files (see #745 for more details). To fix this,
we now fully isolate each path of the tree during the import process.
This leads to more accurate, though unfortunately slightly less
performant, rule matching. The only time a builder is reused now is if
two input files have the same `applies_in` value, in which case they are
merged together.

I have added tests to ensure correctness and prevent a regression. I
also was careful to make sure no previous tests broke in any way (all
changes to existing tests were made in isolation, and thus are not
affected by the logic changes). As far as I can tell, the only behavior
change is that now some previously-ignored rules will now be applied,
which could, in very rare configurations, lead to files being
unintentionally ignored. However, due to the aforementioned logic bug,
those files were all ignored by git already, so I suspect the number of
people actually caught off guard by this change to be extremely low,
likely zero.

Fixes #745.
2023-12-30 14:12:59 +13:00
Félix Saparelli f65a0d21ba
Fix CLI release workflow more (#740) 2023-12-20 01:06:41 +00:00
Félix Saparelli aa0bf1c24f
Fix CLI release workflow when dispatching (#739) 2023-12-19 23:09:48 +00:00
Félix Saparelli 0a6811f1fb
Update cargo.lock (#738) 2023-12-19 22:34:29 +00:00
github-actions[bot] e9cce54179
release: watchexec-cli v1.24.2 (#736)
Co-authored-by: github-actions <github-actions@github.com>
2023-12-19 13:10:59 +00:00
github-actions[bot] 6ecc5569e4
release: watchexec-supervisor v1.0.3 (#735)
Co-authored-by: github-actions <github-actions@github.com>
2023-12-19 11:31:34 +00:00
Félix Saparelli eb4f2ce201
Fix queueing behaviour (#734) 2023-12-19 11:22:59 +00:00
Félix Saparelli b4a64a096a
Add eyra support as a feature (#728) 2023-12-13 14:08:03 +13:00
github-actions[bot] a72ff0e142
release: watchexec-cli v1.24.1 (#722)
Co-authored-by: github-actions <github-actions@github.com>
2023-12-11 12:30:05 +00:00
Félix Saparelli 53c9e344eb
Fix argfile regression (#720) 2023-12-11 17:05:38 +13:00
Félix Saparelli e4e8d39546
Graceful quit on Ctrl-C (#721) 2023-12-11 01:21:57 +00:00
github-actions[bot] 4026938c18
release: watchexec-filterer-tagged v1.0.0 (#719)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-12-10 22:45:04 +00:00
Félix Saparelli 0557d70963
watchexec-filterers: fix bad publish (#715) 2023-12-09 11:24:00 +00:00
github-actions[bot] 477d59d319
release: watchexec-cli v1.24.0 (#699)
Co-authored-by: Félix Saparelli <felix@passcod.name>
Co-authored-by: github-actions <github-actions@github.com>
2023-12-09 10:52:40 +00:00
github-actions[bot] a166b3bc9f
release: watchexec-supervisor v1.0.2 (#713)
Co-authored-by: github-actions <github-actions@github.com>
2023-12-09 10:43:55 +00:00
github-actions[bot] deb6072a26
release: watchexec-signals v2.1.0 (#711)
Co-authored-by: github-actions <github-actions@github.com>
2023-12-09 23:25:41 +13:00
Félix Saparelli 709dbe5151
New option: --signal-map (#710) 2023-12-09 09:30:58 +00:00
Félix Saparelli 03460a6181
More logging for CLI and Supervisor (#709) 2023-12-09 09:10:11 +00:00
github-actions[bot] 44d794c921
release: watchexec-supervisor v1.0.1 (#708)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-11-29 06:10:10 +00:00
github-actions[bot] c75134d255
release: watchexec-events v2.0.1 (#707)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-11-29 05:56:23 +00:00
github-actions[bot] e90bf3756e
release: watchexec v3.0.1 (#706)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-11-29 05:41:27 +00:00
github-actions[bot] 91b34bc96e
release: watchexec-signals v2.0.0 (#705)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-11-29 05:18:03 +00:00
github-actions[bot] c4dceb2d88
release: watchexec-events v2.0.0 (#704)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-11-29 05:15:33 +00:00
Félix Saparelli 16be20050b
Amend readmes (#702) 2023-11-28 11:30:33 +00:00
Félix Saparelli 0e94f220e3
Tweaks to help (#700) 2023-11-27 12:57:01 +00:00
Félix Saparelli 9af9189ac4
Add --quiet, --timings, --colo[u]r, --bell (#698) 2023-11-27 12:12:51 +00:00
github-actions[bot] 16e606e944
release: watchexec-filterer-globset v2.0.0 (#696)
Co-authored-by: github-actions <github-actions@github.com>
2023-11-27 10:52:28 +00:00
Félix Saparelli dc91e69966
Fix bosion readme (#697) 2023-11-27 10:51:51 +00:00
Félix Saparelli 2751caeb39
Add --ignore-nothing (#695) 2023-11-27 10:50:39 +00:00
github-actions[bot] e7580b0a35
release: watchexec-filterer-ignore v2.0.0 (#694)
Co-authored-by: github-actions <github-actions@github.com>
2023-11-27 10:38:06 +00:00
Félix Saparelli 63562fe64d
Add --only-emit-events (#691) 2023-11-27 23:29:55 +13:00
github-actions[bot] d9f6d20b6b
release: watchexec v3.0.0 (#692)
Co-authored-by: github-actions <github-actions@github.com>
2023-11-26 04:54:43 +00:00
github-actions[bot] fb2c5449af
release: watchexec-supervisor v1.0.0 (#690)
Co-authored-by: github-actions <github-actions@github.com>
2023-11-26 04:23:20 +00:00
github-actions[bot] 64bdf7c9d5
release: ignore-files v1.3.2 (#689)
Co-authored-by: github-actions <github-actions@github.com>
2023-11-26 04:22:00 +00:00
github-actions[bot] 65e2db31bc
release: watchexec-events v1.1.0 (#688)
Co-authored-by: github-actions <github-actions@github.com>
2023-11-26 03:33:47 +00:00
github-actions[bot] f66aa5d808
release: project-origins v1.2.1 (#687)
Co-authored-by: github-actions <github-actions@github.com>
2023-11-26 03:30:39 +00:00
github-actions[bot] efacb29f86
release: watchexec-signals v1.0.1 (#686)
Co-authored-by: github-actions <github-actions@github.com>
2023-11-26 03:29:53 +00:00
github-actions[bot] 10556dea11
release: bosion v1.0.2 (#685)
Co-authored-by: github-actions <github-actions@github.com>
2023-11-26 03:29:49 +00:00
Félix Saparelli 87ca5d6b20
Dependabot: add supervisor and remove tagged filterer (#684) 2023-11-26 16:21:13 +13:00
Félix Saparelli 318f850e9b
Remove obsolete release order (#683) 2023-11-26 03:15:29 +00:00
Félix Saparelli b54cd60146
Update all changelogs (#682) 2023-11-26 03:01:13 +00:00
Félix Saparelli 89e3d60ecf
Clippy nursery (#681) 2023-11-26 02:40:57 +00:00
Félix Saparelli a13bc429eb
Watchexec lib v3 (#601)
Co-authored-by: emilHof <95590295+emilHof@users.noreply.github.com>
2023-11-25 20:33:44 +00:00
Felix Yan 7f23fbd68a
Update Arch Linux package URL in packages.md (#679) 2023-11-21 23:26:59 +00:00
dependabot[bot] 652b8c9b2f
Bump actions/checkout from 3 to 4 (#651)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-05 16:05:40 +12:00
github-actions[bot] 19a3fc9189
release: watchexec-cli v1.23.0 (#647)
Co-authored-by: github-actions <github-actions@github.com>
2023-08-30 06:18:56 +00:00
Félix Saparelli 3639f06745
Add --no-discover-ignore (#645) 2023-08-30 04:21:13 +00:00
Félix Saparelli 1aaff8d319
Re-add `-d` short flag (#635) 2023-08-30 04:04:53 +00:00
Félix Saparelli 345eda871b
Skip search for ignores when not needed (#644) 2023-08-30 04:01:23 +00:00
Félix Saparelli 4c3b9f0960
Clippy and update lockfile (#646) 2023-08-30 03:43:57 +00:00
github-actions[bot] 96bf3d231e
release: bosion v1.0.1 (#623)
Co-authored-by: github-actions <github-actions@github.com>
2023-07-02 23:47:13 +00:00
dependabot[bot] afe317d4ee
Update gix-config requirement from 0.24.0 to 0.25.1 in /crates/ignore-files (#622)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-30 10:33:37 +12:00
dependabot[bot] a91d80141b
Update gix requirement from 0.47 to 0.48 in /crates/bosion (#621)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-30 10:33:26 +12:00
Kian-Meng Ang 402d1ba4f9
Fix some typos (#617) 2023-06-26 22:12:24 +00:00
dependabot[bot] 0f2f5f4ea6
Update gix-config requirement from 0.22.0 to 0.24.0 in /crates/ignore-files (#614)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-26 13:10:47 +12:00
Jiahao XU f08002aaf6
dep: bump gix from v0.44.1 => v0.47 (#619) 2023-06-25 23:01:16 +00:00
korrat d72fc38e62
Use raw_arg for CMD on Windows (#616) 2023-06-24 14:10:00 +00:00
dependabot[bot] 2a3a3dee5f
Update clap_complete_nushell requirement from 0.1.10 to 4.3.1 in /crates/cli (#598)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-04 21:00:10 +12:00
dependabot[bot] 6552e3cd7e
Update shadow-rs requirement from 0.21.0 to 0.22.0 in /crates/cli (#597)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-04 20:59:11 +12:00
Félix Saparelli 31b9c2fb91
Fix logfile not creating if it doesn’t exist (#591) 2023-06-04 20:58:58 +12:00
github-actions[bot] d25ae71787
release: ignore-files v1.3.1 (#600)
Co-authored-by: github-actions <github-actions@github.com>
2023-06-04 20:53:24 +12:00
Jonathan Cammisuli 638cddcf83
handle relative paths when using Ignore programmatically (#599) 2023-06-03 20:24:39 +12:00
github-actions[bot] eb19f83761
release: watchexec-cli v1.22.3 (#590)
Co-authored-by: github-actions <github-actions@github.com>
2023-05-14 10:51:37 +00:00
github-actions[bot] 1d87097b3e
release: watchexec-filterer-ignore v1.2.1 (#589)
Co-authored-by: github-actions <github-actions@github.com>
2023-05-14 10:04:52 +00:00
github-actions[bot] 7c1c726d85
release: ignore-files v1.3.0 (#588)
Co-authored-by: github-actions <github-actions@github.com>
2023-05-14 09:31:05 +00:00
Félix Saparelli 0b50c91a1c
Fix warnings (#586) 2023-05-14 08:24:57 +00:00
Félix Saparelli 03b3aef9b7
Add recent PRs to changelogs (#587) 2023-05-14 06:30:34 +00:00
Félix Saparelli 0a1e5781cc
Try to fix windows tests (#585) 2023-05-14 18:02:57 +12:00
Félix Saparelli af2e1562f1
Update completions/manpage (#584) 2023-05-14 17:36:28 +12:00
Félix Saparelli 1028caa389
Update deps (#583) 2023-05-14 05:17:14 +00:00
Jonathan Cammisuli 6a86caacf2
Fix adding globs to the IgnoreFilter (#581) 2023-05-14 16:59:59 +12:00
Jonathan Cammisuli 0afb5f2796
fix bosion tests (#582) 2023-05-11 09:53:42 +12:00
Jonathan Cammisuli 3e79957ad3
Handle nested gitignores (#580) 2023-05-08 22:13:04 +00:00
dependabot[bot] e6f2dcdf48
Update gix requirement from 0.42.0 to 0.44.1 in /crates/bosion (#577)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-06 23:41:19 +00:00
dependabot[bot] f9042808ab
Update embed-resource requirement from 1.6.1 to 2.1.1 in /crates/cli (#566)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-06 23:40:20 +00:00
dependabot[bot] 299a01dcf6
Bump enumflags2 from 0.7.5 to 0.7.7 (#573)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-07 11:26:18 +12:00
dependabot[bot] b9c052d10e
Update gix-config requirement from 0.19.0 to 0.22.0 in /crates/ignore-files (#576)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-07 11:26:02 +12:00
dependabot[bot] bccc0292a0
Bump h2 from 0.3.16 to 0.3.17 (#572)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-14 06:09:51 +12:00
Caleb Schoepp 8e91d26ef6
Update clearscreen requirement from 2.0.0 to 2.0.1 in /crates/lib (#570) 2023-04-06 00:48:48 +00:00
github-actions[bot] e8391cd1d0
release: watchexec-cli v1.22.2 (#560)
Co-authored-by: github-actions <github-actions@github.com>
2023-03-22 11:37:49 +00:00
Félix Saparelli 8a2808027f
Normalise paths to unix on windows for filtering only (#558) 2023-03-22 10:55:19 +00:00
Félix Saparelli 38109b8128
Disable signals on windows (#559) 2023-03-22 23:54:53 +13:00
Félix Saparelli 7e06e2d91d
Build manpage just before packaging (#557) 2023-03-22 04:46:19 +00:00
Félix Saparelli 4d081848a7
Fix tests-pass job (#556) 2023-03-22 04:40:38 +00:00
Félix Saparelli 1979d4400d
Update manpage (#555) 2023-03-22 04:28:43 +00:00
Félix Saparelli 7330827db4
Fix dist-manifest gen (#554) 2023-03-22 04:26:15 +00:00
Félix Saparelli 955562062f
Switch away from set-output (#553) 2023-03-22 04:23:48 +00:00
github-actions[bot] 4294bd42da
release: watchexec-cli v1.22.1 (#551)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-03-22 03:54:07 +00:00
github-actions[bot] f0d115f600
release: watchexec v2.3.0 (#550)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-03-22 02:02:01 +00:00
Félix Saparelli ce9c5d6b22
Always add changelog section even if it's not used later (#552) 2023-03-22 01:55:16 +00:00
Félix Saparelli 59044a5cba
Add Outcome::Race (#548) 2023-03-22 14:47:26 +13:00
Félix Saparelli 483b29af8e
Kill process on drop when using command-group (#549) 2023-03-22 01:35:46 +00:00
Félix Saparelli c166823cb6
Log important beats as info (#547) 2023-03-22 01:23:00 +00:00
dependabot[bot] 79b28d0264
Update dirs requirement from 4.0.0 to 5.0.0 in /crates/cli (#543)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-21 13:16:06 +13:00
Félix Saparelli e06dc0dd16
Fix release final step (#541) 2023-03-18 16:05:14 +00:00
Félix Saparelli f15ea8a825
Fix release scripts (#540)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-03-18 15:36:49 +00:00
github-actions[bot] bfb0a0648a
release: watchexec-filterer-tagged v0.3.0 (#539)
Co-authored-by: github-actions <github-actions@github.com>
2023-03-18 15:06:57 +00:00
github-actions[bot] c337ebca86
release: watchexec-cli v1.22.0 (#538)
Co-authored-by: github-actions <github-actions@github.com>
2023-03-18 15:06:47 +00:00
github-actions[bot] a3ebfcceef
release: watchexec-filterer-globset v1.2.0 (#537)
Co-authored-by: github-actions <github-actions@github.com>
2023-03-18 13:38:37 +00:00
github-actions[bot] cba452edf2
release: watchexec-filterer-ignore v1.2.0 (#536)
Co-authored-by: github-actions <github-actions@github.com>
2023-03-18 12:58:14 +00:00
github-actions[bot] 7444ec133f
release: watchexec v2.2.0 (#535)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-03-19 01:34:55 +13:00
github-actions[bot] 26679721aa
release: ignore-files v1.2.0 (#534)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-03-19 01:08:22 +13:00
github-actions[bot] d8f997e104
release: watchexec-events v1.0.0 (#533)
Co-authored-by: github-actions <github-actions@github.com>
2023-03-18 11:27:38 +00:00
github-actions[bot] d6ae98e644
release: watchexec-signals v1.0.0 (#532)
Co-authored-by: github-actions <github-actions@github.com>
2023-03-18 11:09:41 +00:00
Félix Saparelli 9ae16187f0
Set new crates to zero for release (#531) 2023-03-18 10:43:29 +00:00
Félix Saparelli 5c63a99013
Fix and adjust docs (#530) 2023-03-18 10:23:46 +00:00
Félix Saparelli 80e18ea145
Rename --manpage to --manual (#529) 2023-03-18 22:34:33 +13:00
Félix Saparelli 8156864bf3
--emit-events-to (#515) 2023-03-18 21:32:24 +13:00
dependabot[bot] 64ad4e31f5
Update gix-config requirement from 0.18.0 to 0.19.0 in /crates/ignore-files (#526)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-18 21:22:58 +13:00
dependabot[bot] 7383679fbc
Update gix requirement from 0.40.0 to 0.42.0 in /crates/bosion (#528)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-18 21:22:48 +13:00
dependabot[bot] d866ee615f
Update gix requirement from 0.39.0 to 0.40.0 in /crates/bosion (#523)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-10 11:39:19 +13:00
dependabot[bot] f83790bce3
Update gix-config requirement from 0.17.0 to 0.18.0 in /crates/ignore-files (#518)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-05 17:17:11 +13:00
dependabot[bot] d5fb5bfe26
Update gix requirement from 0.38.0 to 0.39.0 in /crates/bosion (#517)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-05 17:16:54 +13:00
Félix Saparelli 0fe17e036a
Bosion test on windows (#521) 2023-03-05 04:06:24 +00:00
github-actions[bot] 639bef9e31
release: bosion v1.0.0 (#520)
Co-authored-by: github-actions <github-actions@github.com>
2023-03-05 03:47:58 +00:00
Félix Saparelli 690b32f030
Add bosion to releaser (#519) 2023-03-05 16:29:54 +13:00
Félix Saparelli f76b16c4f4
Add bosion crate: build-time info (#516) 2023-03-05 03:26:23 +00:00
Félix Saparelli 14f53a6bf5
Clap 4 and revamp manpage, completions (#513) 2023-03-05 14:57:34 +13:00
Félix Saparelli 1e72cf6866
Revert "Fix #375: urgent events bypass throttle" (#514) 2023-03-03 15:34:15 +00:00
Félix Saparelli c87a7343b3
Update deps (#511) 2023-03-04 04:21:38 +13:00
Félix Saparelli e841333c07
Fix #375: urgent events bypass throttle (#509) 2023-03-02 07:18:34 +00:00
David Perez 70beb51ab5
Switch to gix-config because git-config is deprecated (#502)
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-03-02 16:17:19 +13:00
Félix Saparelli 46453a2b35
Ditch MSRV policy (#510) 2023-03-02 15:33:39 +13:00
Rikard Hjort 6232c213a9
update package name (#507) 2023-02-26 07:02:33 +00:00
Félix Saparelli ca0c300193
Update effective MSRV (#505) 2023-02-22 22:23:00 +00:00
Félix Saparelli b8a8b2265e
releng: Checksum to individual files, write dist-manifest.json (#500) 2023-02-15 04:34:06 +00:00
github-actions[bot] d4b86366a2
release: watchexec-cli v1.21.1 (#499)
Co-authored-by: github-actions <github-actions@github.com>
2023-02-14 23:56:59 +00:00
github-actions[bot] 84d3947247
release: watchexec v2.1.1 (#498)
Co-authored-by: github-actions <github-actions@github.com>
2023-02-14 23:04:21 +00:00
Félix Saparelli 5850c284ca
Exit explicitly when we're PID 1 (#497) 2023-02-15 11:29:54 +13:00
Félix Saparelli 90eb9cae03
Reset process sigmask for Rust 1.66 (#494) 2023-02-15 11:11:57 +13:00
dependabot[bot] 2c06f06ee1
Bump tokio from 1.23.1 to 1.24.2 (#491)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-10 15:55:29 +13:00
Félix Saparelli d6b1d36c6e
Avoid looping in demo (#486) 2023-01-21 08:56:42 +00:00
Félix Saparelli d92a7eb675
Add #449 to lib changelog (#481) 2023-01-11 15:43:28 +00:00
Félix Saparelli 950f302ebf
Lock CI for msrv checks (#482) 2023-01-12 04:35:34 +13:00
dependabot[bot] 19f5bd0d1e
Update git-config requirement from 0.14.0 to 0.15.0 in /crates/ignore-files (#480)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 15:36:43 +13:00
github-actions[bot] 2479aaec4f
release: watchexec-cli v1.21.0 (#478)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-01-09 01:09:21 +00:00
github-actions[bot] 4e3e7a140a
release: watchexec-filterer-tagged v0.2.0 (#477)
Co-authored-by: github-actions <github-actions@github.com>
2023-01-09 00:34:40 +00:00
github-actions[bot] daa11aad09
release: watchexec-filterer-globset v1.1.0 (#476)
Co-authored-by: github-actions <github-actions@github.com>
2023-01-09 00:32:37 +00:00
Félix Saparelli 7ba37b3964
Update PR advice for auto-merge; add meta comment (#475) 2023-01-09 00:20:59 +00:00
github-actions[bot] 7a8680e937
release: watchexec-filterer-ignore v1.1.0 (#474)
Co-authored-by: github-actions <github-actions@github.com>
2023-01-09 00:15:16 +00:00
github-actions[bot] ac2a14fd80
release: watchexec v2.1.0 (#472)
Co-authored-by: github-actions <github-actions@github.com>
2023-01-09 00:01:35 +00:00
Félix Saparelli 2523bf5a65
Add PR trigger on auto-merge enable (#473) 2023-01-08 23:59:46 +00:00
github-actions[bot] 33f5ba5ef9
release: ignore-files v1.1.0 (#471)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-01-08 17:12:08 +00:00
github-actions[bot] f55d669e3c
release: project-origins v1.2.0 (#470)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-01-08 16:05:49 +00:00
Félix Saparelli a23b924be2
Remove remnants of the old release flow that now break things (#469) 2023-01-08 15:23:31 +00:00
Félix Saparelli 404386e795
Add guide for crate release order (#468) 2023-01-08 15:16:00 +00:00
dependabot[bot] 5d0920c5c9
Bump tokio from 1.21.0 to 1.23.1 (#467) 2023-01-07 00:10:45 +00:00
Felix Uellendall f3305c5484
Add usecase to README (#460)
Co-authored-by: Félix Saparelli <felix@passcod.name>
2023-01-06 14:20:16 +00:00
dependabot[bot] 2387318ea2
Update command-group requirement from 1.0.8 to 2.0.1 in /crates/lib (#462)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-07 03:18:16 +13:00
dependabot[bot] 50c1832b35
Update git-config requirement from 0.12.0 to 0.14.0 in /crates/ignore-files (#464)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-07 03:18:01 +13:00
dependabot[bot] 60a5992e7a
Update clearscreen requirement from 1.0.9 to 2.0.0 in /crates/lib (#463)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-07 03:17:48 +13:00
dependabot[bot] 97694c05f5
Bump taiki-e/install-action from 1 to 2 (#461)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-07 03:17:33 +13:00
Félix Saparelli 81d59b62bc
Add to changelogs for libs (#466) 2023-01-06 14:14:42 +00:00
malteneuss af5742945b
Add complex converter tool wrapper example to docs (#458) 2023-01-06 14:06:40 +00:00
Félix Saparelli dc98370492
Clippy fixes (#465) 2023-01-07 02:53:49 +13:00
Félix Saparelli 6d65c05e35
Add openSUSE and MINGW packages (#453) 2022-12-02 23:16:56 +00:00
Félix Saparelli 75da1a61ed
Update contrib guide (#452) 2022-12-02 23:07:36 +00:00
Félix Saparelli 04a8ee22bd
Add apt.cli.rs to install methods (#451) 2022-12-02 22:44:04 +00:00
Michael Jones f613ba1a79
Add option to exit when stdin ends (#449)
Co-authored-by: Félix Saparelli <felix@passcod.name>
2022-12-01 23:19:04 +00:00
dependabot[bot] db287c49f7
Update git-config requirement from 0.7.1 to 0.12.0 in /crates/ignore-files (#448) 2022-11-24 23:25:38 +00:00
dependabot[bot] e6bde7a48d
Bump axum-core from 0.2.7 to 0.2.9 (#439) 2022-11-24 23:13:36 +00:00
dependabot[bot] c30fd84c02
Bump mathieudutour/github-tag-action from 6.0 to 6.1 (#435)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-25 12:04:04 +13:00
dependabot[bot] b25cf1586c
Bump softprops/action-gh-release from cd28b0f5ee8571b76cfdaa62a30d51d752317477 to 1 (#447)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-24 12:35:27 +13:00
dependabot[bot] 46fba794c1
Bump cargo-bins/release-pr from 1 to 2 (#441)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-14 16:12:24 +00:00
dependabot[bot] d350f91b12
Bump softprops/action-gh-release from 50195ba7f6f93d1ac97ba8332a178e008ad176aa to cd28b0f5ee8571b76cfdaa62a30d51d752317477 (#438)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-13 21:45:59 +13:00
Aarni Koskela bb44b3d2dc
Readme: fix CI badge URL (#419)
The previous badge was broken. :)
2022-09-18 21:27:03 +00:00
Robert Laverty ec1cf13a41
Fix zsh autocomplete after using --shell=bash (#417) 2022-09-15 03:17:35 +00:00
Félix Saparelli 6f4c8604e8
Update release versioning 2022-09-07 18:35:00 +12:00
Félix Saparelli cf80b8395f
Learn some build optimisations from binstall (#416) 2022-09-07 06:00:08 +00:00
github-actions[bot] c7c9b30636
release: watchexec-cli v1.20.6 (#415)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2022-09-07 05:30:28 +00:00
github-actions[bot] 695b36e345
release: watchexec v2.0.2 (#414)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2022-09-07 05:08:20 +00:00
Félix Saparelli 4397aa5c7e
Default release pr version to patch 2022-09-07 16:54:40 +12:00
Félix Saparelli dd882109f8
Enable OIDC 2022-09-07 16:53:28 +12:00
Félix Saparelli 014e6246ac
Checkout before setting up signing 2022-09-07 16:52:19 +12:00
Félix Saparelli 8b4e5ef71f
Debug gitsign 2022-09-07 16:48:48 +12:00
Félix Saparelli 236fac4c99
Document the absolute crate release order (#413) 2022-09-07 16:40:47 +12:00
Félix Saparelli b2ea64d436
Use gitsign for release-pr commits (#412) 2022-09-07 16:40:31 +12:00
github-actions[bot] 4ef180f486
release: watchexec-filterer-globset v1.0.1 (#410)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2022-09-07 04:31:39 +00:00
github-actions[bot] 6642362025
release: watchexec-filterer-tagged v0.1.1 (#411)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2022-09-07 04:11:47 +00:00
github-actions[bot] d168ed9676
release: ignore-files v1.0.1 (#407)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2022-09-07 03:50:18 +00:00
Félix Saparelli 91a12383fd
Use gnu tar on windows CI (#409) 2022-09-07 03:41:34 +00:00
github-actions[bot] c46187f92d
release: project-origins v1.1.1 (#408)
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Félix Saparelli <felix@passcod.name>
2022-09-07 03:29:23 +00:00
Félix Saparelli 24a3a3c2f2
Deps: update miette and git-config (#406) 2022-09-07 02:52:53 +00:00
Félix Saparelli 669ad6a7bf
Ditch actions-rs (#395) 2022-09-07 02:15:38 +00:00
Félix Saparelli f7d38206e3
Configure dependabot (#394) 2022-09-07 01:28:15 +00:00
Félix Saparelli 6c40113e9e
Run cargo update (#392) 2022-09-07 13:15:38 +12:00
Félix Saparelli 1042cba39c
Mention library crate changelog 2022-09-07 13:06:04 +12:00
github-actions[bot] 79bcf6838d
release: watchexec v2.0.1 (#390)
Co-authored-by: github-actions <github-actions@github.com>
2022-09-07 00:57:50 +00:00
Félix Saparelli b2b3bb8fde
Merge check, bors, and main tests 2022-09-07 12:36:55 +12:00
Félix Saparelli a49b38c9fd
Only include release notes for cli 2022-09-07 12:31:08 +12:00
Félix Saparelli e9d24688e1
Re-order readmes to prioritise package managers 2022-09-07 12:24:44 +12:00
Félix Saparelli b2de641f20
Document known packagings 2022-09-07 12:15:40 +12:00
Félix Saparelli 475063c49f
Mention package managers 2022-09-07 11:30:42 +12:00
Félix Saparelli 05458c3452
Undo escaping 2022-09-07 11:29:26 +12:00
Félix Saparelli 174af8665f
Remove bors, use cargo-bins/release-pr 2022-09-07 11:24:53 +12:00
Félix Saparelli f684db57ee
Update Notify to stable (#384) 2022-09-02 09:12:47 +00:00
github-actions[bot] ce68338381 release: project-origins v1.1.0 (#385)
This is a release PR for **project-origins** to version **1.1.0**.

Upon merging, you will still need to manually publish the cargo crate.

```
$ cd crates/project-origins
$ cargo publish
```

To merge this release, review the changes then say:

| bors r+ p=10 |
|:-:|
2022-08-24 09:23:52 +00:00
Félix Saparelli 94deab9452 Update binstall metadata (#383) 2022-08-24 07:19:02 +00:00
Félix Saparelli 34184f925a Add some more project types to project-origins (#370) 2022-08-24 07:19:00 +00:00
github-actions[bot] f866e6f498 release: cli v1.20.5 (#374)
This is a release PR for **cli** to version **1.20.5**.

Upon merging, this will automatically build the CLI and create a GitHub release. You still need to manually publish the cargo crate.

```
$ cd crates/cli
$ cargo publish
```

To merge this release, review the changes then say:

| bors r+ p=10 |
|:-:|

---

_Edit release notes into the section below:_

<!-- do not change or remove this heading -->
### Release notes

- Fix: mimalloc was set as the global allocator in the watchexec library, instead of leaving it to downstreams. (#369)
- Releng: s390x and ppc64le targets were added to be prebuilt. (#373)
2022-08-03 23:10:41 +00:00
Félix Saparelli bcba352603 Move mimalloc allocator init to CLI (#369) 2022-08-03 13:11:00 +00:00
Dirk Haubenreisser 90c601deeb Add s390x and ppc64le release-cli build artifacts (#373)
Signed-off-by: Dirk Haubenreisser <haubenr@de.ibm.com>

This PR adds artifact builds for platforms s390x and ppc64le to the GH workflow for target 'release-cli'.
Adding these platforms to the list of pre-built release binaries is instrumental in enabling paketo.io buildpacks for s390x and ppc64le.
2022-08-03 11:27:28 +00:00
github-actions[bot] bb9021eec7 release: cli v1.20.4 (#366)
This is a release PR for **cli** to version **1.20.4**.

Upon merging, this will automatically build the CLI and create a GitHub release. You still need to manually publish the cargo crate.

```
$ cd crates/cli
$ cargo publish
```

To merge this release, review the changes then say:

| bors r+ p=10 |
|:-:|

---

_Edit release notes into the section below:_

<!-- do not change or remove this heading -->
### Release notes

- Remove CLI help tests. They'll be replaced with brand new integration testing that's not obnoxious. (#362, #363, #365)
- Fix the install filenames for first-party RPM packagings, and possibly for DEBs as well. (#292, #364)
2022-07-01 14:13:39 +00:00
Félix Saparelli ea9f5ff694 Fix release replacements (#365)
bors r+
2022-07-01 13:57:46 +00:00
Félix Saparelli c0c9193dff Fix bin filename for deb/rpm packaging (#364)
Unsure if deb ever supported that but rpm sure does not.

Fixes #292
2022-07-01 13:39:43 +00:00
Félix Saparelli f0d64f07df Remove CLI help tests (#363)
Fixes #362

I've been working to remake the tests better / actually valuable but this is a quick "fix" for that issue... in any case help tests would have been gone anyway.
2022-07-01 13:39:43 +00:00
Félix Saparelli f548fd1956 Fix release notes using multiline output (#361) 2022-06-29 04:52:45 +00:00
github-actions[bot] f9ec29a60b release: cli v1.20.3 (#359)
This is a release PR for **cli** to version **1.20.3**.

Upon merging, this will automatically build the CLI and create a GitHub release. You still need to manually publish the cargo crate.

```
$ cd crates/cli
$ cargo publish
```

To merge this release, review the changes then say:

| bors r+ p=10 |
|:-:|

---

_Edit release notes into the section below:_

<!-- do not change or remove this heading -->
### Release notes

- Dependencies are set manually for first-party deb and rpm packages, so they should install without error. A note that these are provided on a best-effort basis and not tested; when available you should prefer your distribution's packaging. (#292, #358)

Co-authored-by: Félix Saparelli <felix@passcod.name>
2022-06-29 03:48:50 +00:00
Félix Saparelli 96825a6f5a Automatic release notes for CLI (#360) 2022-06-29 02:21:57 +00:00
Félix Saparelli e15fa6cd21 Manually set depends for deb and rpm packages (#358)
Should fix #292
2022-06-29 01:28:29 +00:00
github-actions[bot] 64895132aa release: cli v1.20.2 (#357)
This is a release PR for **cli** to version **1.20.2**.

Upon merging, this will automatically build the CLI and create a GitHub release. You still need to manually publish the cargo crate.

```
$ cd crates/cli
$ cargo publish
```

To merge this release, review the changes then say:

| bors r+ p=10 |
|:-:|
2022-06-28 14:15:48 +00:00
Félix Saparelli 1b70a92162 Fix restart (actually issue a stop outcome) (#353)
Fixes #346
2022-06-28 13:50:56 +00:00
Félix Saparelli 1d2dd7b904 Fix env/shell for windows CLI build (#356)
bors r+
2022-06-28 13:40:21 +00:00
Félix Saparelli 94f4dd26c2 Review logging levels: make info more useful (#354)
Fixes #260
2022-06-28 13:40:20 +00:00
Félix Saparelli 5079f45198 Dispatch CLI release job from commit message, not job output (#355) 2022-06-28 13:25:10 +00:00
github-actions[bot] 50e2f0acbf release: cli v1.20.1 (#352)
This is a release PR for **cli** to version **1.20.1**.

Upon merging, this will automatically build the CLI and create a GitHub release. You still need to manually publish the cargo crate.

```
$ cd crates/cli
$ cargo publish
```

To merge this release, review the changes then say:

| bors r+ p=10 |
|:-:|
2022-06-28 12:43:58 +00:00
Félix Saparelli 4970646f1a Fix logging initialisation (#348)
- Fixes #345 (first crash, related to `RUST_LOG` being set)
- Adds multiple warnings when non-standard logging or build options are set
- Fixes the (internal) crate name of the cli so that the log target `watchexec_cli` works
- Fixes the verbosity config to target the actual crate names (snake vs kebab case)
- Fixes a usage error related to tracing's `log` compatibility
2022-06-28 12:21:19 +00:00
Félix Saparelli 3aa128c4ee Fix new instances of clap being way more strict now (#350) 2022-06-28 12:11:29 +00:00
Félix Saparelli 75784667bc Allow non-UTF8 input for paths and extensions (#349)
- Fixes #345 (second crash)
- Proper fix instead of #347
2022-06-28 01:17:17 +00:00
Félix Saparelli ede4959102
Fix CLI release workflow (#339, #340, #341, #342, #343) 2022-06-24 14:40:57 +12:00
github-actions[bot] 77d4b03398 release: cli v1.20.0 (#337)
This is a release PR for **cli** to version **1.20.0**.

Upon merging, this will automatically build the CLI and create a GitHub release. You still need to manually publish the cargo crate.

```
$ cd crates/cli
$ cargo publish
```

To merge this release, review the changes then say:

| bors r+ p=10 |
|:-:|
2022-06-23 09:57:55 +00:00
github-actions[bot] d71412cd12 release: filterer-tagged v0.1.0 (#336)
This is a release PR for **filterer-tagged** to version **0.1.0**.

Upon merging, you will still need to manually publish the cargo crate.

```
$ cd crates/filterer/tagged
$ cargo publish
```

To merge this release, review the changes then say:

| bors r+ p=10 |
|:-:|
2022-06-23 09:24:07 +00:00
github-actions[bot] 9c343a6eb2 release: filterer-globset v1.0.0 (#335)
This is a release PR for **filterer-globset** to version **1.0.0**.

Upon merging, you will still need to manually publish the cargo crate.

```
$ cd crates/filterer/globset
$ cargo publish
```

To merge this release, review the changes then say:

| bors r+ p=10 |
|:-:|
2022-06-23 03:33:20 +00:00
Félix Saparelli 69464d373f Fix release PR instructions again (#334)
See edit history of #333
2022-06-23 00:49:43 +00:00
github-actions[bot] 5cf89eb7b4 release: filterer-ignore v1.0.0 (#333)
This is a release PR for **filterer-ignore** to version **1.0.0**.

Upon merging, you will still need to manually publish the cargo crate.

```
$ cd crates/filterer/ignore
$ cargo publish
```

To merge this release, review the changes then say:
| bors r+ p=10 |
|:-:|
2022-06-23 00:40:59 +00:00
Félix Saparelli 6c3cb476a8 Polish up filterer crates for release (#331) 2022-06-22 23:48:46 +00:00
Félix Saparelli 4f808a1002 Remove prefix on tag (ffs) (#330) 2022-06-17 00:47:06 +00:00
github-actions[bot] c3df998895 release: lib v2.0.0 (#329)
This is a release PR for **lib** to version **2.0.0**.

Upon merging, you will still need to manually publish the cargo crate.

```
$ cd crates/crates/lib
$ cargo publish
```

To merge this release, review the changes then say:

`bors r+ p=10`

Co-authored-by: Félix Saparelli <felix@passcod.name>
2022-06-17 00:29:33 +00:00
Félix Saparelli 0e13595f08 Roll lib changelog on release (#328) 2022-06-17 00:10:10 +00:00
Félix Saparelli 334c704cc4 Add direct link to latest release in README.md (#327) 2022-06-16 23:58:52 +00:00
Félix Saparelli d79a080ad1 Check readme codeblock (#325) 2022-06-16 23:18:31 +00:00
Félix Saparelli 5c2c80a6e0 Add --delay-run (#324)
The other side of #79
2022-06-16 22:55:25 +00:00
Félix Saparelli 92d05755c9 Add Outcome::Sleep (#323)
One half of #79
2022-06-16 16:07:27 +00:00
Félix Saparelli adc4a0a576 Add --log-file so logs are easier to collect (#321) 2022-06-16 15:56:59 +00:00
Félix Saparelli f0e05f9526 Remove obsolete bin/ scripts (#322) 2022-06-16 15:46:32 +00:00
Félix Saparelli ba86225ad4 Make it possible to pass multiple Commands (library) (#320) 2022-06-16 15:36:08 +00:00
Félix Saparelli 361e5530c5 Fix EOF error in release PR action (#319) 2022-06-16 11:34:58 +00:00
Félix Saparelli 4562c0f2f9 release: ignore-files v1.0.0 (#318)
Co-authored-by: github-actions <github-actions@github.com>
2022-06-16 11:09:16 +00:00
Félix Saparelli 03ee184d41 Import changelog for the library to a file (#316) 2022-06-16 10:48:29 +00:00
Félix Saparelli e1d1940261 Handle multi-line commit messages in release-tag workflow (#315) 2022-06-16 10:48:28 +00:00
Félix Saparelli 5ee0356e34 Don’t allow invalid UTF-8 arguments (#317) 2022-06-16 10:19:09 +00:00
github-actions[bot] b133486c66 release: project-origins v1.0.0 (#314)
This is a release PR for **project-origins** to version **1.0.0**.

  Upon merging, you will still need to manually publish the cargo crate.

```
$ cd crates/project-origins
$ cargo publish
```

To merge this release, review the changes then say:

```
bors r+
```
2022-06-16 09:01:22 +00:00
Félix Saparelli 18dea4b6e6
Fix release merge instructions 2022-06-16 20:54:21 +12:00
Félix Saparelli e98989f099
Almost there 2022-06-16 20:28:07 +12:00
Félix Saparelli f21b45e6aa
CI fixes
- #308
- https://github.com/github-community/community/discussions/18697
- #309
- #310
- #311
- #312
- #313
2022-06-16 18:27:28 +12:00
Félix Saparelli 35cf63bc85 Split into more crates (#307) 2022-06-15 03:25:05 +00:00
Félix Saparelli 70aa48c59d Upgrade to clap 3 (#304)
This is just the upgrade, including the new option categories. Move to the derive API or more advanced features is left for later.
2022-06-11 08:05:11 +00:00
Félix Saparelli ae2718ec4d Upgrade to miette 4 (#303) 2022-06-11 07:55:43 +00:00
Félix Saparelli 0e1a6f2c45 Mark Cargo.lock as binary for merging (#305) 2022-06-11 07:38:31 +00:00
Félix Saparelli 446a8d95a7 Replace event queue with a priority queue (#302)
Solves several issues, generally through delivering signals before filesystem events, preventing situations where an overwhelming amount of events makes it impossible to quit.

Does _not_ solve the problem of a queue full of lower-priority events not accepting an urgent message, but that's a rarer issue that's more complicated to overcome.

Changes the Filterer trait: adds Priority to `check_event()`

Makes some events unfilterable (Urgent priority): SIGINT, SIGTERM, and CTRL_C to the main process. These still need to be handled by `on_action` to do anything, but cannot be stopped before reaching that.
2022-06-11 06:43:11 +00:00
Félix Saparelli 62e79fbf7a Add log feature to tracing (#300) 2022-06-07 12:15:17 +00:00
Félix Saparelli 557efab1c4 Document the format of the globset tuple arguments (#298) 2022-06-07 11:46:07 +00:00
Félix Saparelli e215e2c09f Add folder/file ignore and filter tests to globset (#299) 2022-06-07 11:25:50 +00:00
Félix Saparelli ec26a99b7d Fix watchexec example in docs found in #295 (#297) 2022-06-07 09:19:16 +00:00
Félix Saparelli f3e0f0cbda Update readme badge for bors (#289) 2022-05-30 03:19:42 +00:00
Félix Saparelli 84eb92b82e Separate check on main (#288) 2022-05-30 03:07:21 +00:00
Félix Saparelli 3d19ce04e7 Specify full name for bors builds (#287) 2022-05-30 02:59:14 +00:00
Félix Saparelli d395faeefa Test with MSRV on all platforms (#286) 2022-05-30 02:44:50 +00:00
Félix Saparelli 4be340a4bc Configure bors (#285) 2022-05-30 02:34:22 +00:00
Félix Saparelli edf023c009 cli: v1.19.0 2022-04-15 15:49:58 +12:00
Félix Saparelli c58d66bec5 Link manpage from readme 2022-04-15 15:47:44 +12:00
Félix Saparelli 396424112e Add new options to help 2022-04-15 15:45:17 +12:00
Félix Saparelli 3523925c1e Reorganise manpage options into categories 2022-04-15 15:45:17 +12:00
Félix Saparelli f60a623a44 Add --env and --workdir options 2022-04-15 15:45:17 +12:00
Félix Saparelli 6f3cdac9fd Document --project-origin in man 2022-04-15 15:45:17 +12:00
Félix Saparelli 515d5568b2 Document feature 2022-04-15 15:45:17 +12:00
Félix Saparelli 84aac2243c Add --project-origin override 2022-04-15 15:45:17 +12:00
Félix Saparelli 4a6d4350c5 Always install release tools 2022-04-15 15:45:17 +12:00
Félix Saparelli 00e9b17043 Final change to --debounce default: down to 50ms
Closes #168
2022-04-15 15:45:17 +12:00
Félix Saparelli d4acb9d719 Add notice for change to $SHELL-as-default in 2.0
Ref #210
2022-04-15 15:45:17 +12:00
Félix Saparelli 009ef2356f Deny 2018 idioms 2022-04-13 22:59:43 +12:00
Félix Saparelli b374de6097 cli: v1.18.12 2022-04-13 09:22:53 +12:00
Félix Saparelli 6b0f626441 Document project origin behaviour in man 2022-04-13 09:09:13 +12:00
Félix Saparelli 036d9a27e8 Ignore homedir if discovered as origin unless explicitly requested
Fixes #276
2022-04-12 21:59:05 +12:00
Félix Saparelli 98348be8b5 lib: v2.0.0-pre.14 2022-04-04 11:47:36 +12:00
David Calavera 20597802ad
Remove git2 as a dependency (#267)
This dependency cannot be sent between threads.
Instead use git-config which is a pure rust implementation to read git config files.

Uses the builtin values::Path struct to extract ignore paths.
It takes care of all the corner cases with how git interprets paths.
2022-04-04 11:43:30 +12:00
Félix Saparelli e8d3bb964c cli: v1.18.11 2022-03-28 10:29:14 +13:00
Félix Saparelli 386e01b06f The thing I said should never fail does in fact fail
Fixes #271
2022-03-28 10:14:54 +13:00
Félix Saparelli 57e2ddf9fa cli: v1.18.10 2022-03-27 18:23:06 +13:00
Félix Saparelli d38428f297 Look up project origin on implicit pwd
This may cause some more issues to crop up while waiting for --project-origin,
but it is the more correct behaviour.

Fixes #270
2022-03-27 16:31:58 +13:00
Félix Saparelli 7baf79e929 cli: v1.18.9 2022-03-18 15:18:58 +13:00
Félix Saparelli 3969264e91 lib: v2.0.0-pre.13 2022-03-18 15:00:02 +13:00
Félix Saparelli 71f2e38ecb Use cargo-install gh task 2022-03-18 14:12:23 +13:00
Félix Saparelli 07bf2523b6 Revert mac to fsevents 2022-03-18 14:08:59 +13:00
Félix Saparelli 572fc53793 cli: v1.18.8 2022-03-16 16:24:19 +13:00
Félix Saparelli bd3d7a8411 Update man 2022-03-16 16:23:57 +13:00
Félix Saparelli 29dcd418ba lib: v2.0.0-pre.12 2022-03-16 16:10:33 +13:00
Félix Saparelli e5731abde0 Use exact version reqs for prereleases
I did not realise that Cargo considers -pre.1 and -pre.2 to be
compatible, so the latest Notify prerelease broke all existing
releases, and whenever I release a new lib it may break all CLI
versions if the API changes.
2022-03-16 16:02:29 +13:00
Félix Saparelli aeb699b658 Show CLI version in debug logs 2022-03-16 00:01:32 +13:00
Félix Saparelli da22d34274 Fix #262: document env var ordering and other specifics 2022-03-15 23:26:37 +13:00
Félix Saparelli 17edfe663b Add library version to debug log 2022-03-15 23:25:54 +13:00
Félix Saparelli 223d29fa4a Update lockfile 2022-03-14 12:58:02 +13:00
Félix Saparelli 465895ddec Upgrade notify 2022-03-14 12:57:49 +13:00
Félix Saparelli 5e6adabf8d Use kqueue on mac 2022-03-14 12:50:46 +13:00
Félix Saparelli a3c03b9fac cli: v1.18.7 2022-03-07 21:41:30 +13:00
Félix Saparelli ce449d85e2 Require test snapshots to change for bin release 2022-03-07 21:39:54 +13:00
Félix Saparelli 9ff5875327 lib: v2.0.0-pre.11 2022-03-07 20:59:47 +13:00
Félix Saparelli 72100217e8 Allow */foo filters to match foo (compat)
This is buggy behaviour that exists in <=1.17, and this patch restores it*

Per gitignore rules, this glob:

    */somefile

Will match:

    foo/somefile
    bar/somefile

But not:

    somefile

However, so far we’ve accepted this. As this is a breaking change, this patch
introduces a hack which lets us accept this behaviour, but clearly marks it as
a compatibility exception. In 2.0, this will be gone.

Fixes #258

* It only restores it on unices, because the behaviour cannot be restored in
  any reasonable manner on Windows. Ah well. It's not for long anyway.
2022-03-07 20:33:29 +13:00
Félix Saparelli 03aef187bd Let --exts and --filter work together
These two options are meant to work together: they are a union of filters
rather than competing. Thus:

    --exts toml,py --filter Gemfile

will match all of:

    foo.toml
    bar.py
    Gemfile

rather than matching no files at all because Gemfile doesn’t have an extension.

Fixes #259
2022-02-22 02:26:46 +13:00
Félix Saparelli 4af6865ef0 Add broken tests for regressions
See #258 and #259
2022-02-12 22:39:40 +13:00
Félix Saparelli 93da1ce780 Carry help through elevated errors properly
This might show the help text twice actually. Let's see...
2022-02-12 20:05:19 +13:00
Félix Saparelli b77da446d8
Split known create errors to get proper help text 2022-02-12 19:49:02 +13:00
Félix Saparelli 3b64a41d80
Split fs watcher errors into their own enum 2022-02-12 19:37:24 +13:00
Félix Saparelli 56380154d3
Clippy 2022-02-11 00:52:35 +13:00
Félix Saparelli 797a7fc708 Setup cargo-release 2022-02-10 01:40:32 +13:00
Félix Saparelli e5bb99a60b
Add shout-outs to friends of watchexec 2022-02-08 14:59:41 +13:00
Félix Saparelli bd7a933906 cli: v1.18.6 2022-02-07 17:34:26 +13:00
Félix Saparelli bdcbe5ca3c lib: v2.0.0-pre.10 2022-02-07 17:18:21 +13:00
Félix Saparelli 55c02567e0 Bump lib version in cli if in pathed mode 2022-02-07 17:18:09 +13:00
Félix Saparelli 96a6a6e9d9 Revert ignoring .git only when Git is discovered
And so on from other VCS. This causes confusion (ref #255) when watching
from outside a git repo, where the VCS type isn’t detected so the .git
folder is included in the watchset. While slightly incorrect, it’s more
expected that these folders be ignored regardless, and there’s always
--no-default-ignore to avoid those ignores if needed.
2022-02-07 17:15:27 +13:00
Félix Saparelli 94b21c2da3 Load global ignores even when there’s no discovered VCS
Fixes #255
2022-02-07 17:15:27 +13:00
Félix Saparelli 965030b47b Add help text to FsWatcherCreate on Linux
See #251
2022-02-07 17:15:27 +13:00
Félix Saparelli e40744f033 Elevate FsWatcherCreate errors to critical
See #251
2022-02-07 17:15:27 +13:00
Félix Saparelli c6f230a168 Pretty-print runtime errors 2022-02-07 17:15:27 +13:00
Félix Saparelli 427e4a0d08 Change on_error to let the handler raise a CriticalError 2022-02-07 17:15:27 +13:00
Félix Saparelli 8ebcf083b8 Start work on 1.18.6 2022-01-31 19:15:30 +13:00
Félix Saparelli a890b0c916 Deduplicate paths in summarise_events_to_env
Fixes #253
2022-01-31 02:14:28 +13:00
Félix Saparelli ba64fb3c38 cli: v1.18.5 2022-01-31 00:49:45 +13:00
Félix Saparelli ada9888fdf Use lib pre.9 2022-01-31 00:45:47 +13:00
Félix Saparelli bc50c198b3 lib: v2.0.0-pre.9 2022-01-31 00:35:27 +13:00
Félix Saparelli d7a305fc4c
Only run one outcome worker at a time 2022-01-31 00:05:43 +13:00
Félix Saparelli 2a9ee4de0b
Add detailed logging to process holder 2022-01-31 00:05:10 +13:00
Félix Saparelli 9a736c5eb9
Use newly &self Supervisor.wait to drop wait loop 2022-01-31 00:04:56 +13:00
Félix Saparelli 995d38078e
Use a tokio::watch in the supervisor to avoid races 2022-01-31 00:00:51 +13:00
Félix Saparelli 3e942c4d19
Double-check the ongoing atomic 2022-01-30 22:29:33 +13:00
Félix Saparelli fdf4dcd13e
Provide opportunities for process holder to be queried concurrently to a wait() 2022-01-29 04:14:51 +13:00
Félix Saparelli 12ef0411f8
Don't log an error from outcome worker on graceful exit 2022-01-29 04:13:28 +13:00
Félix Saparelli 328700dd72
Stop holding supervisor handle 2022-01-29 04:13:08 +13:00
Félix Saparelli c74eab5e91 Split up action in mods 2022-01-29 02:39:06 +13:00
Félix Saparelli cc0c0be45a
Save a pointer by passing around an Arc<[T]> instead of Arc<Vec<T>> 2022-01-29 02:17:23 +13:00
Félix Saparelli 22f081a47b Spawn outcome apply separately from action loop 2022-01-29 02:08:34 +13:00
Félix Saparelli 10b31a0269 Wrap Supervisor in a RwLock 2022-01-29 02:08:34 +13:00
Félix Saparelli a651d149b0 Replace AtomicTakes with HandleLocks in action 2022-01-29 02:08:34 +13:00
Félix Saparelli b8ffa0c38a Formatting 2022-01-29 02:08:34 +13:00
Félix Saparelli 9845d48464 Add HandlerLock wrapper
This lets a Handler be shared (via a Tokio mutex)
2022-01-29 02:08:34 +13:00
Félix Saparelli d9006a240d Remove keep_* config methods 2022-01-29 02:08:25 +13:00
Félix Saparelli c444895593
Move swaplock to the root 2022-01-28 23:32:54 +13:00
Félix Saparelli 18a2b204e2 Hide io::errors when "waiting on process group" 2022-01-27 10:48:24 +13:00
Félix Saparelli c79d2726ba Disable Windows ARM64 builds
They're consistently failing, needs debugging.
2022-01-26 10:25:33 +13:00
Félix Saparelli 7ccd3c92e0 cli: v1.18.4 2022-01-26 10:04:09 +13:00
Félix Saparelli e6d80558f8 Use lib pre.8 2022-01-26 10:03:53 +13:00
Félix Saparelli fc40336db7 lib: v2.0.0-pre.8 2022-01-26 10:01:15 +13:00
Félix Saparelli a6c997f470
globset: Always pass non-path events (#248) 2022-01-26 09:59:53 +13:00
Félix Saparelli 366277c6c1 Add issue templates 2022-01-26 08:10:14 +13:00
Félix Saparelli 96a41e1b4c
Remove unused Result<> return 2022-01-26 03:24:15 +13:00
Félix Saparelli 77ee59a9e3 cli: v1.18.3 2022-01-26 02:36:27 +13:00
Félix Saparelli d067b5a5de Use lib pre.7 2022-01-26 02:36:01 +13:00
Félix Saparelli f6a3b76d92 lib: v2.0.0-pre.7 2022-01-26 02:33:28 +13:00
Félix Saparelli a5e756df7c Remove unused check_glob utility 2022-01-26 01:58:01 +13:00
Félix Saparelli 59d8388d7e globset: allow multipath events through if any path passes the filter 2022-01-26 01:51:48 +13:00
Félix Saparelli 42d64d0a6d
Fail all folders on extension check 2022-01-26 01:18:32 +13:00
Félix Saparelli 6cebaf204f Restore shell default to sh on unix (#240) 2022-01-26 01:06:18 +13:00
Félix Saparelli 94b4dffc02
Merge pull request #243 from abitrolly/patch-1
cli/README.md: Need glob pattern to ignore subdirs
2022-01-25 23:23:51 +13:00
Anatoli Babenia 8c8cdf8e82
cli/README.md: Need glob pattern to ignore subdirs 2022-01-25 13:21:41 +03:00
Félix Saparelli 5bdd87dbf6
Merge pull request #242 from aeolyus/main
Fix spawing -> spawning typo
2022-01-25 22:40:48 +13:00
Richard Huang 67452152c2
Fix spawing -> spawning typo 2022-01-24 21:52:16 -08:00
Félix Saparelli a51979b54e cli: v1.18.2 2022-01-24 20:53:20 +13:00
Félix Saparelli 9b866ad9e8
Remove default signal from clap, leave it for parse
Fixes #239
2022-01-24 20:52:29 +13:00
Félix Saparelli b8b2c2ca70 Fix citation versioning 2022-01-23 21:55:09 +13:00
Félix Saparelli b5c16f291e cli: v1.18.1 2022-01-23 21:53:29 +13:00
Félix Saparelli 4e7e75e1d5 Strip leading period if present from -e exts (#236) 2022-01-23 21:53:12 +13:00
Félix Saparelli c79a3bd12c Upgraded fmt 2022-01-22 14:00:42 +13:00
Félix Saparelli 187c696d8f Fix release workflow 2022-01-19 00:25:45 +13:00
Félix Saparelli 7effd1a61e cli: v1.18.0 2022-01-19 00:05:03 +13:00
Félix Saparelli 7d60b1689e Use lib pre.6 2022-01-19 00:04:41 +13:00
Félix Saparelli a3fd743786 lib: v2.0.0-pre.6 2022-01-19 00:00:46 +13:00
Félix Saparelli 631c328a55 Use version for lib dependency 2022-01-18 23:56:10 +13:00
Félix Saparelli c58333496e Fail files with no extension on extension check
Instead of passing them, I don't know what I was thinking
2022-01-18 23:56:10 +13:00
Félix Saparelli c367288e38
Add desktop notification to cli feature list 2022-01-18 23:29:28 +13:00
Félix Saparelli c91ab99ac3 lib: v2.0.0-pre.5 2022-01-18 23:27:30 +13:00
Félix Saparelli 9f67ec35b1 More OsSplit windows fixing 2022-01-18 23:14:08 +13:00
Félix Saparelli 881e8f4047 More OsSplit testing 2022-01-18 22:53:24 +13:00
Félix Saparelli 0334b9c9fa Bump msrv in ghaction too 2022-01-18 22:42:19 +13:00
Félix Saparelli 7f092ca4b7 Further windows fix to OsSplit 2022-01-18 22:39:55 +13:00
Félix Saparelli 783da395bb Fix lib readme 2022-01-18 22:38:45 +13:00
Félix Saparelli 8748c062c4 Update deps 2022-01-18 22:21:21 +13:00
Félix Saparelli fd474c7e38
Fix and add tests for OsSplit 2022-01-18 22:10:25 +13:00
Félix Saparelli 044a8244f9
Almost forgot windows... 2022-01-16 20:17:32 +13:00
Félix Saparelli 1d64cac11f Formattting 2022-01-16 20:08:21 +13:00
Félix Saparelli 8bd48c6290
Don't fail if we can't canonicalize an event path
e.g. for deletes
2022-01-16 20:06:44 +13:00
Félix Saparelli 4737937350
Remove generic tagged io error enum variant 2022-01-16 20:01:14 +13:00
Félix Saparelli e2f27a1b01
Add context to last runtime io error
and remove generic runtime io error enum variant
2022-01-16 20:00:07 +13:00
Félix Saparelli 2ea62aec6a
Add context to last critical io error
and remove generic critical io error enum variant
2022-01-16 19:55:57 +13:00
Félix Saparelli bc0fe6be70
Add context to io errors 2022-01-16 19:46:52 +13:00
Félix Saparelli 93a961abf6
Clippy 2022-01-16 19:16:53 +13:00
Félix Saparelli 4085fc522c
Add SpecificIoError trait support for tagged error 2022-01-16 19:16:07 +13:00
Félix Saparelli 44a44a50d1
Move TaggedFiltererError into main error mod 2022-01-16 19:14:31 +13:00
Félix Saparelli b29b3bf1e0
Add helper trait to add context to io errors 2022-01-16 19:09:50 +13:00
Félix Saparelli c821faf383
Split error mod and split generic/specific io errors 2022-01-16 18:57:40 +13:00
Félix Saparelli 6a925fc392
Canonicalise origin and workdir 2022-01-16 17:42:49 +13:00
Félix Saparelli 2a1a386208
Rename (with compat alias) --no-ignore to --no-project-ignore 2022-01-16 17:34:06 +13:00
Félix Saparelli 26e0b60b7b lib: v2.0.0-pre.4 2022-01-16 16:55:55 +13:00
Félix Saparelli 10b71847da
Add support for Pijul and Subversion 2022-01-16 16:13:05 +13:00
Félix Saparelli 9327f8c293
Only ignore .git if we're in a git project, and so on 2022-01-16 16:12:50 +13:00
Félix Saparelli 2682dde41d
Handle errors from ignore file discovery 2022-01-16 16:11:17 +13:00
Félix Saparelli 3d32f2d24b
Hook up new globset signature 2022-01-16 16:09:53 +13:00
Félix Saparelli 561a34d90e
Drop globset::list_from_ignore_file 2022-01-16 15:21:10 +13:00
Félix Saparelli 817f4c2caf
Drop ignorefile tests from globset and tagged now that they're done via common IgnoreFilterer 2022-01-16 15:20:14 +13:00
Félix Saparelli b8d9ad728e
Integrate IgnoreFilterer into GlobsetFilterer 2022-01-16 15:18:15 +13:00
Félix Saparelli d6dfb87063
Integrate IgnoreFilterer into TaggedFilterer 2022-01-16 14:51:35 +13:00
Félix Saparelli 8219e577d0
Reduce swaplock hold for tagged compile globs 2022-01-16 14:51:11 +13:00
Félix Saparelli f073eeb344
Add ::empty() and Clone to IgnoreFilterer 2022-01-16 14:49:14 +13:00
Félix Saparelli 0618eb45fc
Hold swaplock for less in change() 2022-01-16 14:48:29 +13:00
Félix Saparelli ed6df57aa0
Ignore .git, .hg, etc while looking for ignore files 2022-01-16 02:36:22 +13:00
Félix Saparelli 1c388d6b2d
Logic inversione 2022-01-16 02:03:02 +13:00
Félix Saparelli 0c2b4848be
Be more efficient, and more importantly, correct, when ignoring ignores 2022-01-16 01:44:53 +13:00
Félix Saparelli e40b426930 Clippy 2022-01-16 01:44:11 +13:00
Félix Saparelli 63f9eedfec Clippy 2022-01-16 00:58:30 +13:00
Félix Saparelli e9bc4fcf1b
Add ignore support to ignore finder 2022-01-16 00:57:29 +13:00
Félix Saparelli 5bdc1b491f
Add tests for ignore filterer 2022-01-15 23:46:41 +13:00
Félix Saparelli 58d47f78e1
Add more filtering logging and spans 2022-01-15 23:46:06 +13:00
Félix Saparelli 1ce238949e
Reduce verbosity of tracing span output 2022-01-15 16:40:01 +13:00
Félix Saparelli f0435eeaf3
Document envvars read/written and files read 2022-01-15 15:58:30 +13:00
Félix Saparelli 431ef710ee
Expose paths::PATH_SEPARATOR 2022-01-15 15:58:11 +13:00
Félix Saparelli 97070c815c
Add --no-global-ignore to completion and man 2022-01-15 15:57:40 +13:00
Félix Saparelli d70abeac6f
Add --notify to man 2022-01-15 15:26:57 +13:00
Félix Saparelli 78b8acf6cc
Add --print-events to man 2022-01-15 15:26:35 +13:00
Félix Saparelli afb61712a6
Remove --no-shell from completion 2022-01-15 15:26:12 +13:00
Félix Saparelli be5782432a
Add --notify and --print-events to completion 2022-01-15 15:25:47 +13:00
Félix Saparelli da6f9cfc55
Attempt to amend zsh completions for multi-v verbose 2022-01-15 15:20:27 +13:00
Félix Saparelli 775b0ac81c
Add -vv+ usage to manpage 2022-01-15 15:19:16 +13:00
Félix Saparelli 5e285074bd
Add ignore test helper 2022-01-15 15:15:40 +13:00
Félix Saparelli 00def9e19a
Use pretty logging at high -vvvv 2022-01-15 15:14:25 +13:00
Félix Saparelli 2c840f4a2d
Reorganise the ignore mod for brevity 2022-01-15 15:12:32 +13:00
Félix Saparelli 5f43a6eae8
Move profile to where it's effective 2022-01-15 14:34:37 +13:00
Félix Saparelli 0e12030e3b
Perform fat LTO in release 2022-01-13 01:02:37 +13:00
Félix Saparelli 23a3482361
Include some debug info in release, but compress it for prebuilds 2022-01-13 01:02:22 +13:00
Félix Saparelli 0936a68355
Split ignore mod further 2022-01-12 00:59:39 +13:00
Félix Saparelli ca4d4900a9
Add filterer and parser for ignore files 2022-01-12 00:54:21 +13:00
Félix Saparelli 31cbe69051
Configure miette docsurl globally per error type 2022-01-12 00:53:41 +13:00
Félix Saparelli 9527202c51
Add RuntimeError::Set of related errors 2022-01-12 00:52:39 +13:00
Félix Saparelli 6a541e5f27
Move ignore_files one level deeper
in preparation for new ignore functionality
2022-01-10 20:47:06 +13:00
Félix Saparelli 1c99546071
Add lots of logging to ignore file discovery 2022-01-01 01:42:39 +13:00
Félix Saparelli 163bcc3022
Adjust display of errors and exit notify 2022-01-01 01:33:52 +13:00
Félix Saparelli 7fa657fc48
Update cli readme 2021-12-29 22:06:50 +13:00
Félix Saparelli 7fa80f8715 lib: v2.0.0-pre.3 2021-12-29 21:49:07 +13:00
Félix Saparelli d0bb14f39c
Maintain the naming of the env vars 2021-12-29 21:36:42 +13:00
Félix Saparelli d39ffed51e lib: v2.0.0-pre.2 2021-12-29 21:29:30 +13:00
Félix Saparelli 185676cc1e
Fix doctests 2021-12-29 21:21:07 +13:00
Félix Saparelli 9ed3645088
Add environment vars support 2021-12-29 20:55:09 +13:00
Félix Saparelli 53d9a65e5f
Change env summarise to return &str as keys for ease of use 2021-12-29 20:52:17 +13:00
Félix Saparelli ed72c4998e
Add access to events for {Pre,Post}Spawn
Also make access to events read-only (via Arc) for Action
2021-12-29 20:40:12 +13:00
Félix Saparelli 4dbb924977
Add default ignores 2021-12-29 20:14:29 +13:00
Félix Saparelli b5da4e31ba
Add -h testing 2021-12-29 19:56:02 +13:00
Félix Saparelli 736f7f1270
Reorder items in help output
Apparently clap goes by the internal option name, not the display :(
2021-12-29 19:36:40 +13:00
Félix Saparelli a00912f17f
Implement --no-meta for default filterer 2021-12-29 19:29:45 +13:00
Félix Saparelli e2f6fe147a
Support no-{global,project,vcs}-ignore 2021-12-29 19:19:43 +13:00
Félix Saparelli be4b184cd0
Revise --no-ignore and --no-vcs-ignore help text for clarity and conciseness 2021-12-29 19:10:17 +13:00
Félix Saparelli b300be081f
Fix help test files 2021-12-29 19:00:54 +13:00
Félix Saparelli ea3f09408f
Fix new option name 2021-12-29 18:53:47 +13:00
Félix Saparelli ffcdf17914
Implement tagged's --no-meta 2021-12-29 18:51:51 +13:00
Félix Saparelli c45840b657
Load global and -F filter files 2021-12-29 18:39:31 +13:00
Félix Saparelli db322f1228 Fix --help test 2021-12-24 19:14:57 +13:00
Félix Saparelli 75f14ba3d6
Fix OsSplit in windows 2021-12-24 19:07:01 +13:00
Félix Saparelli 08a1e7cc67
Hook up --notify 2021-12-24 19:06:01 +13:00
Félix Saparelli 6f8049dd93
Hook up --ignore, --filter, --exts properly 2021-12-24 18:51:35 +13:00
Félix Saparelli 6cd2252b6c
Modify options available if tagged filterer enabled 2021-12-24 03:56:03 +13:00
Félix Saparelli bb212b413f
Process --no-process-group 2021-12-24 03:47:15 +13:00
Félix Saparelli ec49185488
Split tagged and globset filterer in cli 2021-12-24 03:37:51 +13:00
Félix Saparelli 3bfbcaaa2f
Add test logging and dev-console debugging hints 2021-12-24 02:48:21 +13:00
Félix Saparelli 3f94c3c088
Update project status in Contributing 2021-12-24 02:47:55 +13:00
Félix Saparelli d64135c2c0
Upgrade tracing-subscriber to 0.3 2021-12-24 02:35:26 +13:00
Félix Saparelli c3094eaff8
Upgrade to tokio-console 0.1 2021-12-24 02:28:21 +13:00
Félix Saparelli 0f51a6e794
Test filter files 2021-12-24 02:21:45 +13:00
Félix Saparelli 26254f7022
Add support for "tagged filter files" 2021-12-24 02:20:56 +13:00
Félix Saparelli 8f9492a7bc
Fix filtering when there's both a Glob and a NotGlob match 2021-12-24 02:19:58 +13:00
Félix Saparelli f19dbf945d
Express process end exceptions as hex in filters 2021-12-23 00:32:56 +13:00
Félix Saparelli 9d04143202 lib: v2.0.0-pre.1 2021-12-21 18:19:16 +13:00
Félix Saparelli 401b84db8a Clippy 2021-12-21 18:15:47 +13:00
Félix Saparelli d14e7ff41b
Implement process completion signal matching 2021-12-21 18:05:52 +13:00
Félix Saparelli 8a7699cf2f
Add process completion signal tests 2021-12-21 18:01:51 +13:00
Félix Saparelli e4d669e230
Implement most of process completion matching
(except ExitSignal)
2021-12-21 17:56:14 +13:00
Félix Saparelli e7de00edfe
Change process completion auto op to glob 2021-12-21 17:49:24 +13:00
Félix Saparelli 5856f976db
Add tests for process completion 2021-12-21 17:49:02 +13:00
Félix Saparelli 4323a28852
Implement signal matching 2021-12-21 16:38:57 +13:00
Félix Saparelli ff8b019245
Add tests for signal matchers 2021-12-21 16:29:36 +13:00
Félix Saparelli 8a25ea95af
Add sig alias for signal parsed tag 2021-12-21 16:19:35 +13:00
Félix Saparelli 962c7cd6d6
Test pids 2021-12-21 16:14:58 +13:00
Félix Saparelli 02534defd6
Test feks 2021-12-18 12:53:33 +13:00
Félix Saparelli 946c52b513
Document op and matcher mappings 2021-12-18 12:44:59 +13:00
Félix Saparelli 159a8a4b2e
Change auto op for FEKs to glob 2021-12-18 12:44:40 +13:00
Félix Saparelli ba9d9939d9
Add more aliases for matcher 2021-12-18 12:44:18 +13:00
Félix Saparelli 5ebceddc3e
Start testing nonpaths 2021-12-17 23:29:02 +13:00
Félix Saparelli d38a78631f
Test negation in tagged parser 2021-12-17 23:19:36 +13:00
Félix Saparelli debded9c0e
Add stability note to tagged filterer 2021-12-17 23:19:16 +13:00
Félix Saparelli d6b5dd5ae0
Test parser 2021-12-17 03:57:25 +13:00
Félix Saparelli b59acaa9cf
Start testing parser and nonpaths 2021-12-15 07:24:13 +13:00
Félix Saparelli e4cd1d7379
Test ignorefiles on globset, bugs and all 2021-12-15 06:39:54 +13:00
Félix Saparelli 1af3a1c849
Extract common test helpers 2021-12-15 06:33:55 +13:00
Félix Saparelli 23925db51e
Test scopes 2021-12-15 06:01:40 +13:00
Félix Saparelli 015447e433
Fix whitelisting in pathed globs 2021-12-15 04:57:17 +13:00
Félix Saparelli a4c863baf8
Test ignore files with folders and globs 2021-12-14 01:47:34 +13:00
Félix Saparelli f8250f47de
Suppress supervisor.handle warning 2021-12-10 00:53:18 +13:00
Félix Saparelli 289f76ae6c
Test outcome resolving 2021-12-08 22:07:58 +13:00
Félix Saparelli f229456f88
Specify and test sorting behaviour 2021-12-08 21:43:10 +13:00
Félix Saparelli 89fd99a683
Add multipaths tests 2021-12-08 21:25:03 +13:00
Félix Saparelli e9275702d1
Fix common_path stemming and start testing summarise_events_to_env 2021-12-07 01:14:19 +13:00
Félix Saparelli f304774a4f
Mention windows 11 in manifest 2021-12-07 00:50:56 +13:00
Félix Saparelli a3751519e8
Re-export notify event types 2021-12-07 00:50:33 +13:00
Félix Saparelli 41869af688
Simplify summarise_events_to_env signature (and usage) 2021-12-07 00:49:14 +13:00
Félix Saparelli 0826d531af
Test scoped path glob filtering 2021-12-02 21:33:48 +13:00
Félix Saparelli ce3f2a3cbd
Fix tests/document remaining differences from globset 2021-12-01 01:45:19 +13:00
Félix Saparelli 2d633d9177
Use proper ignore API so path globs match correctly
This notably fixes the v1 "confusing" behaviour when matching folders,
where the expectation is for any of:

folder
folder/
/folder

to match the folder and all paths below it, but v1 would only do this
when *both* of these were added:

**/folder
**/folder/**

Which is very verbose and has caught literally everyone who's ever tried
to do this kinda thing.

The old behaviour is preserved in the globset filterer, for
compatibility, as there are other small behavioural changes that this
affects, even though the new behaviour in the tagged filterer is
arguably the most correct and the old is a bug.
2021-12-01 01:41:07 +13:00
Félix Saparelli 1ff3cbf455
Add lots more logging to add_filter path 2021-11-30 02:11:50 +13:00
Félix Saparelli f3bc5fa6d3
Test globset properly
All paths are canonicalised at entrance, so testing should reflect that
2021-11-30 01:42:00 +13:00
Félix Saparelli 4367380a7c
Ignore failing tests 2021-11-28 02:28:14 +13:00
Félix Saparelli 269894e1b0
Add tests for tagged (paths only)
- v1 buggy tests don't pass
2021-11-28 02:22:07 +13:00
Félix Saparelli 0efdf8ea16
Pull globset tests from v1 2021-11-22 22:22:39 +13:00
Félix Saparelli a46cfba1a2
Pre-add support for logical grouping of options in help
Will work once we switch to clap3
2021-11-22 21:24:59 +13:00
Félix Saparelli a12a83cea2
Fix mistaken assumption in ProcessEnd::from(unix) 2021-10-28 01:03:54 +13:00
Félix Saparelli 745e3baa71
Span tracing in globset filterer check 2021-10-28 01:03:24 +13:00
Félix Saparelli 631b492064
Span tracing in tagged filterer check 2021-10-28 01:01:35 +13:00
Félix Saparelli afd9677441 Add manual trigger to audit and check 2021-10-26 21:14:47 +13:00
Félix Saparelli b13c23c576 Use latest stable toolchain in audit 2021-10-26 21:13:57 +13:00
Félix Saparelli 6d23339dea
Yes but why rely on bits 2021-10-22 06:04:11 +13:00
Félix Saparelli 5c012c5b0c
Fix nonzeros not being bit-opable (windows) 2021-10-22 05:55:28 +13:00
Félix Saparelli 963cd68cc4 Fix cli for ProcessEnd 2021-10-22 05:48:37 +13:00
Félix Saparelli 470cdd698b
Replace ExitStatus with our own type in Event 2021-10-22 05:38:48 +13:00
Félix Saparelli 6671863f2f
Replace std FileType with our own (serde-able) enum 2021-10-20 01:18:43 +13:00
Félix Saparelli 401437784d
Opt in to 2021 ed 2021-10-20 01:00:21 +13:00
Félix Saparelli be37349b90
Bump msrv to 1.56.0 (2021 ed) 2021-10-20 00:48:47 +13:00
Félix Saparelli c84e14825d
Opt into resolver=2 2021-10-20 00:47:41 +13:00
Félix Saparelli c758675728
Prep for folder tests 2021-10-20 00:47:22 +13:00
Félix Saparelli 110e1d4c96
Start a test harness for globset 2021-10-17 17:11:50 +13:00
Félix Saparelli 34d7c5ee9c
Make globset easier to create (less generics) 2021-10-17 17:11:29 +13:00
Félix Saparelli f9cbb11258
Just reset the MSRV to latest stable (1.55), might as well 2021-10-17 04:12:04 +13:00
Félix Saparelli 9d14ad7166
Document that == and != are case-insensitive 2021-10-17 04:03:18 +13:00
Félix Saparelli 96de715cf7
Fix cli test on windows?
This won't matter for long
2021-10-17 03:59:22 +13:00
Félix Saparelli beb87bdbb0
Update MSRV to 1.45
we can do it, it's a breaking...
also, Tokio requirement
2021-10-17 03:58:22 +13:00
Félix Saparelli 489fb612c7
Tagged docs typo 2021-10-17 03:54:48 +13:00
Félix Saparelli 1eb10074ef
Markdown typo 2021-10-17 03:53:05 +13:00
Félix Saparelli 43353fecb2
Fix for windows (unmarked unix-only import) 2021-10-17 03:48:32 +13:00
Félix Saparelli 0b60f5edb5 lib: v2.0.0-pre.0 2021-10-17 03:41:13 +13:00
Félix Saparelli a79de88c58 Merge branch 'main' into tokio 2021-10-17 03:39:19 +13:00
Félix Saparelli 5d57621512
Write readme for 2.0.0-pre.0 2021-10-17 03:37:12 +13:00
Félix Saparelli 70b1a3cd7b
Fix doc links 2021-10-17 03:06:08 +13:00
Félix Saparelli 60fa09182d
Docs: watchexec 2021-10-17 03:01:55 +13:00
Félix Saparelli fae4fbf9a0
Docs: error 2021-10-17 02:32:43 +13:00
Félix Saparelli 17b83fda08
Docs: command 2021-10-17 02:24:36 +13:00
Félix Saparelli fcf6a2154a
Add notes to refer to more precise docs on the RuntimeConfig 2021-10-17 01:22:55 +13:00
Félix Saparelli 88dfc0d664
Add note about logging and error handling to main lib doc 2021-10-17 01:16:41 +13:00
Félix Saparelli 1522aaf409
Docs: action 2021-10-17 01:12:04 +13:00
Félix Saparelli d43165494f
Docs: event 2021-10-16 23:47:00 +13:00
Félix Saparelli 47fc2f30a8
Docs: SubSignal 2021-10-16 23:31:00 +13:00
Félix Saparelli 0ad0845018
Docs: filter 2021-10-16 23:14:57 +13:00
Félix Saparelli 8b8b9674aa
Docs: fs 2021-10-16 20:02:17 +13:00
Félix Saparelli 423caaef2a
Docs: ProjectType 2021-10-16 19:56:38 +13:00
Félix Saparelli e62f313533
Eliminate eyre from doctests too 2021-10-16 19:08:35 +13:00
Félix Saparelli 2225b6d097
Reduce deps featureset 2021-10-16 17:27:21 +13:00
Félix Saparelli 17310ee4b5
Docs: modules 2021-10-16 17:13:32 +13:00
Félix Saparelli e06f615531
Implement basic check_glob() 2021-10-16 17:09:21 +13:00
Félix Saparelli f58e97a62f
Fix globset ignorefile support (wrong field) 2021-10-16 17:01:27 +13:00
Félix Saparelli 5d2f2fcf62
Support the COMMON_PATH variant of the event summariser 2021-10-16 16:54:48 +13:00
Félix Saparelli 30abed3fb2
Add function to import an ignore file in globset filterer format 2021-10-16 16:45:03 +13:00
Félix Saparelli ebabef9eed
Support extensions in globset filterer 2021-10-16 16:37:29 +13:00
Félix Saparelli 19b27959ed
Add globset filterer 2021-10-16 16:26:29 +13:00
Félix Saparelli b2f4d0f244 Port method to summarise events from old source 2021-10-16 15:18:42 +13:00
Félix Saparelli 083c1e2f52 Move common_prefix to its own mod 2021-10-16 13:55:20 +13:00
Félix Saparelli e577b040b9
Handle signalling to sub process on non-unix 2021-10-16 01:21:52 +13:00
Félix Saparelli 92513a4dc3
Add SubSignal type for sending signals to subprocesses 2021-10-16 01:14:17 +13:00
Félix Saparelli 86882e8d27
Add From<&str> for WatchedPath 2021-10-16 01:13:39 +13:00
Félix Saparelli 75243bfdad
Rename Signal to MainSignal
in preparation for another signal type
2021-10-16 01:13:16 +13:00
Félix Saparelli 55e4e1dc58 Review TODOs in the code 2021-10-15 23:00:50 +13:00
Félix Saparelli b780345e8b Use mimalloc for musl builds 2021-10-15 14:27:32 +13:00
Félix Saparelli 948388b019 Reduce featureset of dependencies (tokio,git2) 2021-10-15 14:27:17 +13:00
Félix Saparelli 8f61ac31da
Prep fs pathset for future 2021-10-15 01:38:21 +13:00
Félix Saparelli 14b0364135
Get filetype filters actually working 2021-10-14 01:26:15 +13:00
Félix Saparelli ae6af17aea
Find and load all ignores for watchexec cli 2021-10-14 00:38:56 +13:00
Félix Saparelli 87b6729ab7
Add utility ProjectType::{is_vcs,is_soft} and project::common_prefix fns 2021-10-14 00:14:31 +13:00
Félix Saparelli f24e95504b
Fix panic in tagged filtering 2021-10-14 00:13:48 +13:00
Félix Saparelli c6336cdf3c
Add filetype matcher 2021-10-13 04:06:55 +13:00
Félix Saparelli fb4f136c0d
Match path globs 2021-10-13 04:06:39 +13:00
Félix Saparelli 758ac2dc89
Change panic into a todo 2021-10-13 01:51:09 +13:00
Félix Saparelli fd2edbf11c
Compile gitignore patterns 2021-10-13 01:49:38 +13:00
Félix Saparelli c9da2c133a
Harmonise root/origin 2021-10-13 01:49:11 +13:00
Félix Saparelli f16ba2dff1
Redo and sketch new filter adding process 2021-10-13 00:48:42 +13:00
Félix Saparelli cd7d5f1fcb
Draft and plan ignore loading 2021-10-11 23:34:14 +13:00
Félix Saparelli 3c65aee839
Find project types 2021-10-10 23:35:27 +13:00
Félix Saparelli 1dff1f5644
Find project origins more efficiently 2021-10-10 23:35:11 +13:00
Félix Saparelli 59fe74656a
Stop using eyre even in examples 2021-10-10 21:04:40 +13:00
Félix Saparelli 7af0339871 Detect project origins (if any) 2021-10-10 17:56:49 +13:00
Félix Saparelli 3219be53f5
Add support for bazaar global ignores 2021-10-10 16:06:56 +13:00
Félix Saparelli 65b042ec8f
Discover ignore files for path and for user/env 2021-10-10 16:03:05 +13:00
Félix Saparelli 8bc58ba6b5
Start sketching gitignore support 2021-10-09 18:45:32 +13:00
Félix Saparelli a1fce1b06e
Replace eyre with miette
and upgrade it to 3.2.0
2021-10-09 18:43:51 +13:00
Félix Saparelli 323f2d29ee
Split off filter errors into their own type(s) 2021-10-09 18:41:45 +13:00
Félix Saparelli 3dff065f4b
Add error variants for external custom errors 2021-10-09 18:38:37 +13:00
Félix Saparelli 81bee9513d
Remove derive-builder
* the InitConfigBuilder non-miette error goes away
* creating an InitConfig is no longer faillible for no reason
* the "builder" style is consistent between the two config structs
2021-10-09 18:37:59 +13:00
Félix Saparelli 07878f8357
Implement path filtering 2021-09-30 04:03:46 +13:00
Félix Saparelli 288ce9d2f4
== and != perform case-insensitive comparisons 2021-09-30 02:34:27 +13:00
Félix Saparelli d6b7175bb1 Formattting 2021-09-29 23:43:39 +13:00
Félix Saparelli f93ba29982 Update deps 2021-09-29 23:38:02 +13:00
Félix Saparelli dfb5525c7e Add tokio-console 2021-09-29 01:47:18 +13:00
Félix Saparelli e916ac8050
Add repology badge 2021-09-29 01:43:36 +13:00
Félix Saparelli 45a7ce6aa0
Fix logic error and upgrade warn to panic in debug 2021-09-28 23:44:28 +13:00
Félix Saparelli 6b306a15ab
Add event saturation notes 2021-09-28 22:52:59 +13:00
Félix Saparelli 30dae61a02
Add filtering to demo CLI 2021-09-28 22:25:56 +13:00
Félix Saparelli 7cdb6ac5ad
Bypass filters for empty events 2021-09-28 22:23:48 +13:00
Félix Saparelli f492bca8c3
Add filter add/del error to runtime 2021-09-28 22:23:23 +13:00
Félix Saparelli 9bb6e1356a
Add is_empty and is_internal to Event 2021-09-28 22:22:33 +13:00
Félix Saparelli f673d00e9c
Add logging to filter parser 2021-09-28 22:22:14 +13:00
Félix Saparelli f3c74bd151
Add methods to configure tagger filter 2021-09-28 22:21:51 +13:00
Félix Saparelli 4fda3c477b
Add logging to tagged filter 2021-09-28 22:21:13 +13:00
Félix Saparelli 6e414d1de4
Change the default of Shell 2021-09-28 01:44:20 +13:00
Félix Saparelli 2c894266a8
Add negation filters, and filter application 2021-09-28 00:54:33 +13:00
Félix Saparelli b57fa8b236 Start implementing two Filterers (v1 and v2) 2021-09-23 21:59:35 +12:00
Félix Saparelli 7875b4db67
Provide filterer as trait
which will allow basically anything user-provided as filter, though of
course we'll have (soon) our own fairly comprehensive implementation
2021-09-22 23:39:41 +12:00
Félix Saparelli f1685821a3
Split types out of action 2021-09-18 17:20:05 +12:00
Félix Saparelli 29d0b66ba9
Move filter types out 2021-09-18 17:09:00 +12:00
Félix Saparelli 2be21b6bac
Move filter parser out 2021-09-18 17:07:32 +12:00
Félix Saparelli 84dc77f787 Add parser for filters 2021-09-14 20:11:29 +12:00
Félix Saparelli 6a55f5cc6d
Start on filter types 2021-09-13 19:51:07 +12:00
Félix Saparelli 9e3c8c1f32
Rename particle/culars to tags 2021-09-13 19:34:40 +12:00
Félix Saparelli 59647e64a6
Merge pull request #213 from ethanhs/patch-1
Add arm64 musl build
2021-09-06 08:46:49 +12:00
Ethan Smith c2d57fcf48
Add arm64 musl build 2021-09-05 13:42:20 -07:00
Félix Saparelli e5fcc6553e
Also leave alt buffer on reset 2021-09-04 02:00:57 +12:00
Félix Saparelli 4043ed34ae
Add Reset outcome (#186, #211) 2021-09-04 01:55:25 +12:00
Félix Saparelli 645ab74c62
Implement Outcome::Wait, and CLI on-busy=queue 2021-09-03 09:25:23 +12:00
Félix Saparelli b923638cbd
Correctly watch for process completion 2021-09-03 09:25:06 +12:00
Félix Saparelli 9c8d4c1a1b
Add fs event metadata to event 2021-09-03 08:14:04 +12:00
Félix Saparelli 07f5e445f6
Use Event Display impl in cli 2021-09-03 07:58:20 +12:00
Félix Saparelli 5cbbb7b67f
Add Display impl for events 2021-09-03 07:57:59 +12:00
Félix Saparelli 608aa516b1
Add source to internal event 2021-09-03 07:57:45 +12:00
Félix Saparelli 29e7780fdc
Add process completion handling to cli demo 2021-09-03 05:43:53 +12:00
Félix Saparelli ec6b508894
Ignoring supervisor kill/signal internal errors
As the errors only occur when the process is dead anyway
2021-09-03 05:43:26 +12:00
Félix Saparelli b728bfecfc
Differentiate trace logs when ending supervisor 2021-09-03 05:42:24 +12:00
Félix Saparelli f880b0b38a
Always apply Both outcomes, even when the first fails 2021-09-03 05:41:50 +12:00
Félix Saparelli 8e4994abca
Add process supervisor to watch command to completion
Also change the concept of a completion handler to instead sending a
synthetic "process completed" event down the same path as usual.

That makes handling completion the job of the action handler, but also
means it's immediately possible to launch a process or do an action in
response to the process completing. Win win!
2021-09-03 05:22:15 +12:00
Félix Saparelli 0f247e9e5c
Fix demo for poll option gaining a timeout 2021-09-03 05:18:30 +12:00
Félix Saparelli ef453193af
Add pre-spawn and post-spawn hooks 2021-08-25 04:41:14 +12:00
Félix Saparelli 1fd5c85317 Good idea but let's keep compat for now 2021-08-25 02:40:22 +12:00
Félix Saparelli 6df6d6fd5a Handle signals in cli 2021-08-24 23:19:44 +12:00
Félix Saparelli 7d492fa677
Hide --watch-when-idle from help 2021-08-24 22:56:15 +12:00
Félix Saparelli 70e8a4dff2
Fix cli tests 2021-08-24 22:53:44 +12:00
Félix Saparelli 58b37940b8 Implement most existing options and mark the rest 2021-08-24 22:46:16 +12:00
Félix Saparelli 6767948daa
Specify delay for fs Poll mode 2021-08-24 22:28:29 +12:00
Félix Saparelli 33fb691d29
Add method to insert events into watchexec manually 2021-08-24 22:20:44 +12:00
Félix Saparelli 9cb1f5bf79
Re-export Outcome's Signal type 2021-08-24 21:31:46 +12:00
Félix Saparelli e939f97c90
Move config creation out of arg parsing, and start on using libv2 2021-08-24 20:23:37 +12:00
Félix Saparelli 23d794ed7e
Apply tabs project-wide 2021-08-24 20:22:25 +12:00
Félix Saparelli 33f8b60e46
Take IntoIterator<AsRef<str>> to be more flexible on input 2021-08-24 20:14:01 +12:00
Félix Saparelli 05afb141b6
Add InitConfig::builder() to be a little more idiomatic
Neat side effect: keeps rust-analyzer from complaining about unknown types
(because it doesn't expand the builder macro)!
2021-08-24 19:59:11 +12:00
Félix Saparelli b4ead7f5fb
Report several runtime errors if notify gives us several paths in an error 2021-08-23 06:08:25 +12:00
Félix Saparelli 3588cb4d62
Log fs watch/unwatch errors harder (to reveal paths) 2021-08-23 05:15:55 +12:00
Félix Saparelli 6cb3fc1c9a
Demo switching file watcher backends at runtime 2021-08-23 03:59:02 +12:00
Félix Saparelli 4a9168f5e6
Log on graceful exit 2021-08-23 03:36:10 +12:00
Félix Saparelli 9b94f18890
Fix double-actioning in throttle 2021-08-23 03:12:23 +12:00
Félix Saparelli b42336cb74
Actually watch files in example 2021-08-23 03:11:58 +12:00
Félix Saparelli b2effda341
Update to miette 1.0 beta 2021-08-23 02:37:13 +12:00
Félix Saparelli 5314d201a4
Expand print_out example into watchexec test case 2021-08-23 02:36:58 +12:00
Félix Saparelli 74d8e73817
Fix tokio panic for async handlers 2021-08-23 02:35:28 +12:00
Félix Saparelli 931648a955
Add signals() convenience iter on Event 2021-08-23 02:35:03 +12:00
Félix Saparelli cc5b1c988e
Add some logging to Process 2021-08-23 02:34:44 +12:00
Félix Saparelli 60ed6bba25
Fix infinite loop in action recv code 2021-08-23 02:34:29 +12:00
Félix Saparelli 05117e69fe
Prep for more handlers in action 2021-08-23 02:33:23 +12:00
Félix Saparelli 4843920a36
Protect again starting command without anything in command 2021-08-23 02:32:48 +12:00
Félix Saparelli 17b09d8798
Add graceful exit support 2021-08-23 02:32:08 +12:00
Félix Saparelli f4a8a9fc6a
Print PID in initialisation 2021-08-23 02:30:56 +12:00
Félix Saparelli 18d2487ec3
Rename reconfig to reconfigure 2021-08-23 00:31:39 +12:00
Félix Saparelli 3066ee5913
Implement most of process handling 2021-08-23 00:28:20 +12:00
Félix Saparelli f150c26b22
Add action.grouped config 2021-08-23 00:27:45 +12:00
Félix Saparelli d2d0bb7be2
Resolve compound outcomes 2021-08-22 23:23:01 +12:00
Félix Saparelli 7a709b9b4d
Prefer generic Both combinator than specific ClearAnd 2021-08-22 23:22:27 +12:00
Félix Saparelli c85c164c09
Make the example in lib.rs compile 2021-08-22 22:06:50 +12:00
Félix Saparelli 227c2a0e0d
Add command and shell options to action 2021-08-22 22:06:31 +12:00
Félix Saparelli 613fe24c64
Add paths() convenience iter on Event 2021-08-22 22:06:12 +12:00
Félix Saparelli 8998c40746
Add convenience methods for Outcome's combinators 2021-08-22 22:05:45 +12:00
Félix Saparelli d7d549a4c8
Add convenience modifiers on RuntimeConfig ourselves
It's not exactly a builder, and this lets us flatten all the options at the
top level instead of requiring the user to dig deeper into the
action, fs, etc modules' WorkingData structs.
2021-08-22 22:05:09 +12:00
Félix Saparelli 6c3c06e39c
Stop using Builder for RuntimeConfig 2021-08-22 20:49:24 +12:00
Félix Saparelli 53854d93d4
Change Outcome::OrStart to the more flexible ::IfRunning 2021-08-22 20:47:47 +12:00
Félix Saparelli 656c0d8fd2
Fix action throttling
Specifically, on loop start the timeout would be for the full throttle duration,
which is not correct if some time has passed or the loop goes on recycle
2021-08-22 20:29:57 +12:00
Félix Saparelli 40f6f7397f
Fill out Outcome 2021-08-22 20:27:51 +12:00
Félix Saparelli 5b8611a8c0
Make notes on needed docs 2021-08-22 20:26:48 +12:00
Félix Saparelli 350b85e0c7
Allow an outcome to be determined by the action handler without &mut! 2021-08-22 18:56:57 +12:00
Félix Saparelli 2a0661b122
Call action handler on action 2021-08-22 05:58:03 +12:00
Félix Saparelli 2812a723ff
Write action throttling code 2021-08-22 02:54:02 +12:00
Félix Saparelli ce60be2ec9
Add print_out example 2021-08-22 02:53:31 +12:00
Félix Saparelli f2f138ce9f
Add logging to Watchexec 2021-08-22 02:53:20 +12:00
Félix Saparelli 019018c93e
Add docs for error_handler as it's a bit tricky 2021-08-21 22:30:19 +12:00
Félix Saparelli 816313303a
Finish handlers by implementing the error hook 2021-08-21 20:46:44 +12:00
Félix Saparelli 0f37e42243
Add action worker 2021-08-21 04:43:55 +12:00
Félix Saparelli dcde429787
Improve handlers to not need GATs and provide various impls 2021-08-21 04:43:15 +12:00
Félix Saparelli 9f34492c79
Upgrade to notify pre.12 2021-08-20 02:59:39 +12:00
Félix Saparelli 95ad3e91ff
Add example / aspirational usage to lib doc 2021-08-20 02:56:13 +12:00
Félix Saparelli 6a46c2bff3
Refactor watchexec to only have &self methods and default to wrap it in Arc 2021-08-20 02:55:34 +12:00
Félix Saparelli 249c581dc9
Make channel buffers configurable 2021-08-19 21:28:56 +12:00
Félix Saparelli 5d11ccaa71
Add a bit more structure via documentation 2021-08-19 20:44:02 +12:00
Félix Saparelli 319729582f
Split signal and fs examples 2021-08-19 20:31:29 +12:00
Félix Saparelli 6f3abdeaea
Add RuntimeError::from_handler utility 2021-08-19 20:30:35 +12:00
Félix Saparelli 4e4a8e6853
Add Handler trait 2021-08-19 20:30:01 +12:00
Félix Saparelli 0bb38f40a5
Start off on main interface 2021-08-19 01:12:50 +12:00
Félix Saparelli 826dbd8cda
Make fs::worker Send 2021-08-19 00:40:35 +12:00
Félix Saparelli cae00070fb
Remove chrono dep 2021-08-18 18:54:05 +12:00
Félix Saparelli 0237a568df
Handle signals into events 2021-08-17 21:41:13 +12:00
Félix Saparelli f5e19a6e5f
Adapt Shell command builder 2021-08-17 03:09:22 +12:00
Félix Saparelli 7053360187
Clarify fs worker usage 2021-08-17 01:37:01 +12:00
Félix Saparelli 822148da03
Canonicalise paths + add example 2021-08-17 01:15:17 +12:00
Félix Saparelli f08bdad8ee
Use local datetime on events instead of naive 2021-08-16 21:52:13 +12:00
Félix Saparelli 61fec2cf27
Use lib v1 for cli 2021-08-16 21:49:22 +12:00
Félix Saparelli b15615bbaa
Start on watchexec v2 2021-08-16 21:49:12 +12:00
Félix Saparelli e21a3a99f6 cli: v1.17.1 2021-07-31 06:37:29 +12:00
Félix Saparelli 13140c88c4 Temporarily disable rpm releases 2021-07-31 06:36:57 +12:00
Félix Saparelli 42c34a66a2
Install release tools with --locked 2021-07-31 06:18:47 +12:00
Félix Saparelli c6ec9015f7
Add --notify to test 2021-07-31 05:26:26 +12:00
Félix Saparelli d54d74854e
Add experimental --notify option
See #139
2021-07-31 05:11:42 +12:00
Félix Saparelli a3173194a1
Implement cli's own wrapper handler
That will let us hook in watchexec-cli specific stuff
2021-07-31 04:24:05 +12:00
Félix Saparelli 3208652ed8
Add citation.cff 2021-07-29 00:45:13 +12:00
Félix Saparelli aa99fa1674 Add bin/sign tool 2021-07-22 03:56:31 +12:00
Félix Saparelli bc07ad486d cli: v1.17.0 2021-07-22 03:25:51 +12:00
Félix Saparelli 3948e4e9a0 Cache cargo bin in CI 2021-07-22 03:18:27 +12:00
Félix Saparelli d7b7dcd5f0 Only install deb+rpm tooling on linux 2021-07-22 03:13:00 +12:00
Félix Saparelli 288eba37e0 Use lib 1.17.1 2021-07-22 01:36:56 +12:00
Félix Saparelli bd96803d1e lib: v1.17.1 2021-07-22 01:36:33 +12:00
Félix Saparelli 0ab1405186
Ignore errors when killing command on pre-spawn 2021-07-22 01:36:19 +12:00
Félix Saparelli 7bd99f30df Use lib 1.17.0 2021-07-22 01:18:00 +12:00
Félix Saparelli bf922e36ac lib: v1.17.0 2021-07-22 01:15:46 +12:00
Félix Saparelli d8fb70c454
Cease with the 2015-style #[macro_use]s 2021-07-22 01:01:11 +12:00
Félix Saparelli 66caedf978
Add --no-process-group flag 2021-07-22 00:56:35 +12:00
Félix Saparelli ef36d3429d
Fix expectation in windows path test 2021-07-22 00:47:52 +12:00
Félix Saparelli 73eef67206
Don't rely on bash being installed for windows tests 2021-07-22 00:47:02 +12:00
Félix Saparelli 3485bd7e16
Add windows tests for path/env handling 2021-07-22 00:40:05 +12:00
Félix Saparelli f88c30b854
Another windows test fix 2021-07-22 00:22:39 +12:00
Félix Saparelli 18fdbbcfea Merge branch 'docs/website' 2021-07-22 00:18:13 +12:00
Félix Saparelli 85e2c12c34
Review readmes, add website links 2021-07-22 00:13:59 +12:00
Félix Saparelli 146d49ee8e
Update deps 2021-07-21 23:57:31 +12:00
Félix Saparelli 665f5ef6f0
Remove binstall metadata from the lib 2021-07-21 23:55:10 +12:00
Félix Saparelli d59a76182a
Remove cargo install stub 2021-07-21 23:54:42 +12:00
Félix Saparelli 392547ffa4
Fix typo 2021-07-21 23:47:16 +12:00
Félix Saparelli f5a92220c9
Drop debounce to 100ms (#168) 2021-07-21 23:44:24 +12:00
Félix Saparelli eb59e92b8f
Add support for disabling process groups (#158) 2021-07-21 23:38:42 +12:00
Félix Saparelli bb6a5ae891
Split process.rs into shell and paths
(now that the bulk of process code is gone)
2021-07-21 23:37:24 +12:00
Félix Saparelli 72cda2b0b0
Make sure to kill the old command group before starting a new one 2021-07-21 21:42:55 +12:00
Félix Saparelli 9c20c8c8b5 Replace process code with command-group 2021-07-21 20:22:40 +12:00
Félix Saparelli 4d6ad2cc1f
Use website as source for docs logo 2021-07-20 20:32:38 +12:00
Félix Saparelli 07974e0d14
Implement @argfile argument parsing (#145) 2021-07-17 02:10:03 +12:00
Félix Saparelli 847520357c
Rename ignore test fns 2021-07-17 01:33:39 +12:00
Félix Saparelli 54ac2e9ae0
Use color-eyre for application errors rather than the library's error type 2021-07-17 01:33:04 +12:00
Félix Saparelli 0c25ea0269 cli: v1.16.2 2021-07-10 20:08:45 +12:00
Félix Saparelli 6457df5a0a Use 1.16.1 lib in cli 2021-07-10 20:08:23 +12:00
Félix Saparelli 8368846444 Update deps 2021-07-10 20:07:59 +12:00
Félix Saparelli 7b16a226b2 lib: v1.16.1 2021-07-10 20:04:31 +12:00
Félix Saparelli ba26999028 Pin globset version to avoid breakage
Breakage caused by this fix: https://github.com/BurntSushi/ripgrep/pull/1756

The fix is correct, but it does break a lot of stuff :/
2021-07-10 20:02:37 +12:00
Félix Saparelli 604c24ec38 Link to website for downloads 2021-07-10 03:48:12 +12:00
Félix Saparelli e6c7da3635 Add rpm support with cargo-generate-rpm 2021-07-10 03:48:12 +12:00
Félix Saparelli 1eaaf7e844 Use cargo-deb to replace existing deb kludge 2021-07-10 03:48:12 +12:00
Félix Saparelli 4526ba2cae Merge in cargo watch's release improvements 2021-07-10 03:48:12 +12:00
Félix Saparelli 654a324fdd Set website as website 2021-07-10 03:48:12 +12:00
Félix Saparelli 08d795f841 Remove stub main.rs from library 2021-07-10 03:48:12 +12:00
Félix Saparelli badb27a19c Add release public key 2021-07-10 03:48:12 +12:00
Félix Saparelli bdc2e384fc
Merge pull request #202 from watchexec/on-update/bug-200 2021-07-10 03:47:37 +12:00
Félix Saparelli 585f73adde Poll process completion harder on windows 2021-07-10 03:43:21 +12:00
Félix Saparelli 71a178d4c2 Actually check process when querying for completion
With --on-update=do-nothing, we need to know when the process is done
before we can spawn a new one, but we never actually used to truly check
the process, only the presence or absence of a spawned process. That
process may have already completed, but because we don't wait on it when
in do-nothing mode, there is no opportunity to notice this.

So now we either actually check the completion status of the process (on
Windows), or we expose the `done` mutex value on demand (Unix).
Essentially this adds a way to check the completion status of the
process without blocking (modulo a mutex lock on unix).

Fixes #200
2021-07-10 03:43:21 +12:00
Félix Saparelli 960bbbabbc cli: v1.16.1 2021-05-22 20:05:57 +12:00
Félix Saparelli 695c2e0f1a Update lockfile 2021-05-22 20:00:06 +12:00
Félix Saparelli f0862b9f1e Update to clearscreen 1.0.4 for bugfix 2021-05-22 19:59:32 +12:00
Félix Saparelli d8540d76b8
Fomat and clippy 2021-05-10 23:37:03 +12:00
Félix Saparelli 319727b0a6
It was in the wrong place the whole time! 🤬 2021-05-10 23:27:53 +12:00
Félix Saparelli 7e4ff78bc4
🤦 2021-05-10 23:21:30 +12:00
Félix Saparelli 169de99ee5
Whoops, wrong file 2021-05-10 23:15:14 +12:00
Félix Saparelli 1015c1979a
Update help snapshot version when releasing 2021-05-10 23:10:55 +12:00
Félix Saparelli cb684fc7a8
Fix help snapshot for windows (.exe!) 2021-05-10 23:10:30 +12:00
Félix Saparelli 0d2f28c91a
Add test for cli help 2021-05-10 23:02:31 +12:00
Félix Saparelli eafbc9a77b
Clean up due to removing pubs 2021-05-10 22:44:35 +12:00
Félix Saparelli 324fbe9055
Remove unused cli mod 2021-05-10 22:27:41 +12:00
Félix Saparelli 668d931eac
Remove public interface now that cli is a different crate 2021-05-10 22:26:38 +12:00
Félix Saparelli 6e844cc29a
Turn off panic=abort
This may help in some rare crash cases where system resources could be in an inconsistent state.
2021-05-09 16:29:50 +12:00
Félix Saparelli dc4a31252f
Only check MSRV for library 2021-05-09 04:20:13 +12:00
Félix Saparelli be16d2e6a8
Use published lib in cli for cli publish 2021-05-09 03:54:06 +12:00
Félix Saparelli 9a002be54c
Ignore lib version tags for CI to avoid work duplication 2021-05-09 03:49:57 +12:00
Félix Saparelli ad9f51a24b lib: v1.16.0 2021-05-09 03:46:23 +12:00
Félix Saparelli c517b98782 Split readmes 2021-05-09 03:44:11 +12:00
Félix Saparelli 6a0ac73547 cli: v1.16.0 2021-05-09 02:21:07 +12:00
Félix Saparelli c5c69731c2 Use grep -E for macOS compat 2021-05-09 02:19:53 +12:00
Félix Saparelli 8ebbce5516
Add nix to install section 2021-05-09 01:50:44 +12:00
Félix Saparelli d4e0e93278
Only build cli crate during release 2021-05-09 01:23:06 +12:00
Félix Saparelli 148be31f65
Add a stub to the watchexec (lib) crate to point to the watchexec-cli crate 2021-05-09 01:19:50 +12:00
Félix Saparelli 8295ac7a1c Don't fail CI on clippy warnings 2021-05-08 19:22:35 +12:00
Félix Saparelli 6aebd9b3e7 Formatting 2021-05-08 19:12:13 +12:00
Félix Saparelli 07f56ac7d5
Refactor inotify max watches warning to be less nested and satisfy clippy better 2021-05-08 19:07:56 +12:00
Félix Saparelli d23261673b
Update clearscreen 2021-05-08 18:43:12 +12:00
Félix Saparelli bdc3550a0d
Restrict CI to changes that will cause recompiles 2021-05-01 04:32:42 +12:00
Félix Saparelli 149b9b9821
Split the versioning of the lib and cli (in theory) 2021-05-01 04:22:33 +12:00
Félix Saparelli aeab4159d4
Change semver policy for the library 2021-05-01 03:56:16 +12:00
Félix Saparelli b761118c19
Leave current name on readme 2021-05-01 03:50:33 +12:00
Félix Saparelli 181ca7b5c5
Change crate description for library 2021-05-01 03:47:22 +12:00
Félix Saparelli aff9f2d8f2
Leave binstall config on the lib crate for now 2021-05-01 03:46:36 +12:00
Félix Saparelli 1f3f4ada35 Split into two crates: lib and cli
That has a number of advantages:

- #193 the build.rs is only run for the CLI, so the Windows manifest is
  not embedded in the library anymore, opening it up for downstreams.

- it sets the stage for decoupling the version numbers of the CLI and
  library, to have the library increase its major more often, while the
  CLI retains compatibility further… that is, to have both follow semver

- it removes the CLI-only dependencies from the library

- it makes compilation a bit faster as compiling the library and the
  CLI's other dependencies can happen in parallel

One major disadvantage:

- installing via cargo changes from watchexec to watchexec-cli. Most
  installs are from prebuilt and from packages, but that's still a
  potential stumble.

And of course, the CLI APIs in the library are gone (they were already
deprecated, though).

We also take this opportunity to get rid of the clear_screen code and
use our new clearscreen library. #99 #171 #185
2021-05-01 03:27:17 +12:00
Félix Saparelli 898f83e29c
Add experimental builds for WinARM 2021-05-01 02:26:33 +12:00
Félix Saparelli 5da59b122d
Finish apple m1 prep config 2021-05-01 02:25:10 +12:00
Félix Saparelli 74934f304f 1.15.3 2021-05-01 00:27:44 +12:00
Félix Saparelli db5b662581
Vom
Fixes #192 again
2021-04-30 14:19:19 +12:00
Félix Saparelli 74cec51700
Disable activeCodePage again
Fixes #192
2021-04-30 13:53:25 +12:00
Félix Saparelli 6e2835b8aa
Fix #191: timing suffix is now provided by Duration's Debug impl, so remove it from the message 2021-04-28 14:12:16 +12:00
Félix Saparelli 12184136f7 1.15.2 2021-04-27 02:04:52 +12:00
Félix Saparelli bed43d9e4c
Add compatiblity entries again 2021-04-27 01:59:44 +12:00
Félix Saparelli 97207710cd
Attempt to fix format of metadata section 2021-04-27 01:49:39 +12:00
Félix Saparelli 1fab379cbd
Add back metadata 2021-04-27 01:39:17 +12:00
Félix Saparelli 0db6c97f2d
Add heapType again 2021-04-27 01:33:41 +12:00
Félix Saparelli f30e2fc49e
Add activeCodePage again 2021-04-27 01:28:34 +12:00
Félix Saparelli 73ac954a40
Update ws ns to 2020 2021-04-27 01:23:51 +12:00
Félix Saparelli 1a8d1cb142
Back to only longPath, but in new format? 2021-04-27 01:12:09 +12:00
Félix Saparelli fe4410640d
Only do the manifest settings? 2021-04-27 01:06:37 +12:00
Félix Saparelli 226ef97ad9
Also opt-in to the UTF-8 codepage 2021-04-27 00:53:42 +12:00
Félix Saparelli 150c474b9c
Opt into SegmentHeap to maybe reduce memory use on Windows 2021-04-27 00:34:15 +12:00
Félix Saparelli fa081d97bb
Augment the windows manifest with metadata and OS version compatibility 2021-04-27 00:29:04 +12:00
Félix Saparelli 8decbd63f6 Update lockfile 2021-04-27 00:10:21 +12:00
Félix Saparelli 1b889b3063
Limit version up script to the first version ie ours 2021-04-27 00:09:11 +12:00
Félix Saparelli 34989e6fc2
Add logo 2021-04-26 23:59:43 +12:00
Félix Saparelli a510ecd936 Enable experimental Apple M1 cross builds and downgrade i686 musl to experimental 2021-04-21 10:03:24 +12:00
Félix Saparelli cdcb4e2af4 Show multi command and --shell uses 2021-04-19 09:42:27 +12:00
Félix Saparelli 2603f13fc7 1.15.1 2021-04-17 12:48:21 +12:00
Félix Saparelli 25f02c5777
Add test for Shell::Unix with shopts 2021-04-17 02:19:59 +12:00
Félix Saparelli 1c338adb9d
Generate html manpage with toc style 2021-04-17 02:11:16 +12:00
Félix Saparelli 81b3340f6c
Update lockfile to latest notify patch release 2021-04-17 02:05:04 +12:00
Félix Saparelli 0e26934bbd
Add manpage in HTML format to release packages 2021-04-17 02:04:43 +12:00
Félix Saparelli 591b4a11c2 Remove obsolete brew formula 2021-04-17 02:01:26 +12:00
Félix Saparelli 749bf89b6c Document the argument processing in the manpage
Fixes #82
2021-04-17 02:01:26 +12:00
Félix Saparelli f1c7b555e1 Document the --shell semantics in the manpage 2021-04-17 02:01:26 +12:00
Félix Saparelli 6635635a9c Fix #181 by splitting shell program in Shell::Unix() by ascii space to handle additional args 2021-04-17 02:01:26 +12:00
Félix Saparelli 1b44e7aa87 Extract Shell handling into one method common to both windows and unix 2021-04-17 02:01:26 +12:00
Félix Saparelli a2078e3703 Document the semantics of the Shell variants 2021-04-17 02:01:26 +12:00
Félix Saparelli 3c26e3987c
Merge pull request #189 from mwu-tow/git-root-lookup
Fix lookup of the root git directory
2021-04-13 02:10:32 +12:00
Michał W. Urbańczyk 10429777ce Fixed lookup of the root git directory. 2021-04-12 13:32:57 +02:00
Félix Saparelli 940f4b98d0 Update lockfile 2021-04-11 06:09:48 +12:00
Félix Saparelli 139b6b43c7
Drop debounce to 150ms (#168) 2021-04-11 06:05:28 +12:00
Félix Saparelli 03aad1caaa
Don't run checks on tags 2021-04-11 05:59:42 +12:00
Félix Saparelli 579e53678e 1.15.0 2021-04-11 05:58:32 +12:00
Félix Saparelli d124fdb587
Adjust bin/version to deal with this project's Cargo.toml 2021-04-11 05:53:04 +12:00
Félix Saparelli 6b1ba7aad7
Update dependencies 2021-04-11 05:51:33 +12:00
Félix Saparelli 05e66784ce
Apply clippy recommendations 2021-04-11 05:44:24 +12:00
Félix Saparelli 6ec02d38ab Regenerate manpage 2021-04-11 05:36:43 +12:00
Félix Saparelli b5f56e831d
Formatting 2021-04-11 05:33:30 +12:00
Félix Saparelli f4637892ab
Fix --shell option 2021-04-11 05:29:55 +12:00
Félix Saparelli b0d2a6c875
Bump MSRV to 1.43 2021-04-11 05:17:11 +12:00
Félix Saparelli 15cdd7c754
Use Durations for durations in Config 2021-04-11 05:13:44 +12:00
Félix Saparelli 75ef0095ff
Cosmetic fixes to help 2021-04-11 05:06:32 +12:00
Félix Saparelli 5da11d2fd7 Add more unix shell testing 2021-04-11 05:01:21 +12:00
Félix Saparelli 52284ae866
If you say so, windows 2021-04-11 04:58:38 +12:00
Félix Saparelli 52ca1e98fb Formatting again 2021-04-11 04:55:00 +12:00
Félix Saparelli d37261529c
Moar windows fixes 2021-04-11 04:50:31 +12:00
Félix Saparelli 15806019af
Fix windows compile mistake 2021-04-11 04:44:49 +12:00
Félix Saparelli 0ade9dfc3a
Implement Display for Signal on windows 2021-04-11 04:44:13 +12:00
Félix Saparelli 2e85658a12
Update MSRV to 1.40 for non_exhaustive 2021-04-11 04:38:56 +12:00
Félix Saparelli 5753e7773f
Formatting 2021-04-11 04:32:58 +12:00
Félix Saparelli cdd8a7b91a
Fix process test and add more for windows 2021-04-11 04:32:48 +12:00
Félix Saparelli ced37d7617 Expose on-busy-update in cli args 2021-04-11 04:21:47 +12:00
Félix Saparelli e08f1934ec
Simplify on_update code further 2021-04-11 04:02:14 +12:00
Félix Saparelli d25c374d7f
Clarify the behaviour when receiving updates while running in the code 2021-04-11 03:59:30 +12:00
Félix Saparelli f32943bfd2
Document --watch-when-idle much more thoroughly 2021-04-11 03:31:44 +12:00
Félix Saparelli 1b5bdee08e
Make terminology more consistent and avoid some "kill child" usages 2021-04-11 03:21:38 +12:00
Félix Saparelli 12d130c3f1
Refactor run on_update to make the behaviour clearer 2021-04-11 03:15:17 +12:00
Félix Saparelli 6cfe649228
Document --shell 2021-04-11 02:51:20 +12:00
Félix Saparelli e5cdd51633
Remove/deprecate Config.no_shell 2021-04-11 02:36:38 +12:00
Félix Saparelli 4c29c7a09d
Add --shell option 2021-04-11 02:36:10 +12:00
Félix Saparelli 92060e5655
Expose shell via builder 2021-04-11 02:28:29 +12:00
Félix Saparelli 1280a15ca2
Support powershell and custom shells in the backend 2021-04-11 02:08:39 +12:00
Félix Saparelli 2a382a9486
Rename spawn args positively 2021-04-11 01:44:44 +12:00
Félix Saparelli 7965ccb605
Discard code from attempt at wrapping quotes 2021-04-11 01:40:30 +12:00
Félix Saparelli bbaaff8a1e
Split args from cli in preparation to remove it from lib entirely 2021-04-11 01:33:40 +12:00
Félix Saparelli cd3b8c6cba
Move Args and builder to Config, and deprecate old names 2021-04-11 01:23:24 +12:00
Félix Saparelli 31fd818247
Emit log level separately from Args 2021-04-11 01:09:28 +12:00
Félix Saparelli 757de0d92e
Use ArgsBuilder ourselves 2021-04-11 01:09:06 +12:00
Félix Saparelli 0c6b1bf2e4
Undocument --kill 2021-04-11 01:06:32 +12:00
Félix Saparelli 988acaed65
Hide --kill option 2021-04-11 01:04:47 +12:00
Félix Saparelli 9c1b65e712
Deprecate get_args and get_args_from 2021-04-11 01:04:25 +12:00
Félix Saparelli 7d523dfcf0
Document clear_screen functions 2021-04-11 01:02:44 +12:00
Félix Saparelli c42fe66985
Remove new Args.changes field 2021-04-11 01:02:13 +12:00
Félix Saparelli 426b6a8318
Deprecate Args.debug harder 2021-04-11 01:01:20 +12:00
Félix Saparelli 9968a66042
Hide Args.once harder 2021-04-11 00:58:24 +12:00
Félix Saparelli 268c0cee38
Harmonise defaults between cli and builder 2021-04-11 00:57:46 +12:00
Félix Saparelli 0b79e93c84
Mark cli::Args non-exhaustive so ArgsBuilder usage is mandatory 2021-04-11 00:56:47 +12:00
Félix Saparelli fca038b23c
Reduce lints in favour of stability rather than strictness 2021-04-11 00:55:50 +12:00
Félix Saparelli 1da3a8d26c Add --changes-only to manpage and completions 2021-04-11 00:01:02 +12:00
Félix Saparelli ecd7d1c7e3 Switch to gh actions and clean up metadata and build stuff 2021-04-10 23:53:12 +12:00
Félix Saparelli 3a3ae89046 Add version script 2021-04-10 22:44:11 +12:00
Félix Saparelli 5e4af976de
Merge pull request #180 from nindoja/add_changes_option
Add --changes-only option to only print path change information.
2021-04-09 19:30:53 +12:00
Shane Fry 949fbcf7ae Add --changes-only option to only print path change information. 2021-04-08 12:52:44 -05:00
Félix Saparelli 35e39afb95
Merge pull request #169 from coolaj86/patch-1 2020-10-03 21:45:27 +13:00
Félix Saparelli f99a1a7a38
Normalise install section 2020-10-03 21:44:43 +13:00
AJ ONeal 6414f60b52 add Webi install instructions 2020-10-01 15:23:07 -06:00
Félix Saparelli c8619e34e0 1.14.1 2020-09-30 17:16:54 +13:00
Félix Saparelli 838103fcf2 Embed long paths manifest on windows (#163) 2020-09-30 17:06:41 +13:00
Félix Saparelli 166f0b8fc2
Drop default debounce to 300ms (cf #168) 2020-09-30 16:48:24 +13:00
Félix Saparelli f2da804d3b
Correct --watch help text as per #165 2020-09-15 13:21:02 +12:00
Félix Saparelli 55b03e82c3
Fix #165 by adding example of running against a single file 2020-09-07 02:12:38 +12:00
Félix Saparelli 570ed3afdf
Add windows manifest to enable long path support (#163)
- `requestedPrivileges`: explicitly set privilege level to be the same as parent
- `longPathAware`: opt into transparent long path support on Win10 and above
2020-07-19 16:14:23 +12:00
Félix Saparelli fdb0cfb759 Add soft deprecation on Args.debug 2020-07-04 17:42:13 +12:00
Félix Saparelli 502081203a 1.14.0 2020-07-04 00:57:29 +12:00
Félix Saparelli 2926e956ad Wump winapi to .9 2020-07-04 00:51:51 +12:00
Félix Saparelli 0b5120430c Revise clippy lints to avoid breakage 2020-07-04 00:38:50 +12:00
Félix Saparelli f38e7ab969 Cargo fmt 2020-07-04 00:20:02 +12:00
Félix Saparelli f045fd45ac Mention new --no-meta/--no-env in readme 2020-07-03 23:55:54 +12:00
Félix Saparelli 66555c9b18 Add CONTRIBUTING.md 2020-07-03 23:51:53 +12:00
Félix Saparelli 0b13c39056
Merge pull request #160 from PhilipDaniels/main 2020-07-03 23:32:49 +12:00
Félix Saparelli 0716830374
Merge pull request #157 from qguv/fix-child-env-overflow 2020-07-03 23:19:29 +12:00
Philip Daniels 03142f5ec1 Call init_logger after parsing the args. 2020-06-25 11:16:22 +01:00
Philip Daniels ebd5ec084f Do not call init_logger from inside watch.
And move init_logger to main.rs for future use.
2020-06-24 15:17:59 +01:00
Quint Guvernator 2615a1de7c wrap ioerror when it represents oserror E2BIG 2020-06-24 13:40:11 +02:00
Quint Guvernator cca7b19283 fix some clippy lints 2020-06-24 10:58:15 +02:00
Quint Guvernator 7770de8f7c test: add new arguments to spawn(...) 2020-06-23 15:02:10 +02:00
Quint Guvernator d246114678 add --no-meta switch to avoid some redundant events for #78 2020-06-23 14:41:53 +02:00
Quint Guvernator 524812028d add --no-environment switch to fix #78 2020-06-23 13:43:55 +02:00
Félix Saparelli 6f6fb0ceb2
Merge pull request #156 from thomasetter/main
add Kate (KDE default editor) swap file to default ignores
2020-06-15 15:39:22 +12:00
Thomas Etter c50abc324c add Kate (KDE default editor) swap file to default ignores
.filename.kate-swp format https://unix.stackexchange.com/a/112400
2020-06-14 18:17:13 +02:00
Félix Saparelli b9473c6c86 1.13.1 2020-06-06 15:21:08 +12:00
Félix Saparelli 92029f7365 Fix faulty .git lookup code 2020-06-06 15:16:02 +12:00
Félix Saparelli 80bbea7d21 1.13.0 2020-06-04 19:39:07 +12:00
Félix Saparelli 6a3af92d25 Update deps 2020-06-04 19:38:49 +12:00
Félix Saparelli be6c29c821
Merge pull request #147 from Chris-Nicholls/gitignore 2020-06-04 19:29:53 +12:00
Martin Sehnoutka f8f6c0ac5a Mention time units explicitly in CLI interface
The force-poll flag does not mention time units as opposed to the
debounce flag and to make it even more confusing, the comment in the
code says something else than the output:
*** Polling for changes every 2000 ms

This patch makes it clear what units are used.
2020-04-18 17:15:46 +12:00
Chris Nicholls 2d29a7d7c4 Look for .ignore files in subfolders of watched paths 2020-03-09 10:59:02 +00:00
Chris Nicholls 0175e071e1 Include .gitignores in subdirectories 2020-03-06 10:28:29 +00:00
Félix Saparelli 5843deb573
Allow clippy::too_many_lines 2019-11-19 19:42:20 +13:00
Félix Saparelli 97232cfd09
1.12.0 2019-11-19 19:06:43 +13:00
daubaris 50fa771c41 Adding missed details 2019-11-19 01:15:07 +13:00
daubaris 9a204241f7 Satisfying requested changes 2019-11-19 01:15:07 +13:00
daubaris 7ad8e78a34 Rename the command from 'watch-idle' to 'watch-when-idle' 2019-11-19 01:15:07 +13:00
daubaris de5ed1c2bd #123 --watch-idle flag implementation 2019-11-19 01:15:07 +13:00
Félix Saparelli 90b9a85c0c
Swap out deprecated mem::uninitialized() 2019-11-19 00:38:58 +13:00
Thomas Etter 6e64a2c152 update the test to make sure that files matching part of the ignore are not excluded 2019-11-12 23:36:49 +13:00
Thomas Etter 1c6f5fab89 fix the ignore path handling to match the README by ignoring everything
below a directory
2019-11-12 23:36:49 +13:00
Félix Saparelli 798fd3c0bd
Fix verb tense on help message for `--force-poll` 2019-11-11 09:51:06 +13:00
Félix Saparelli 211bb681f5
1.11.1 2019-10-28 22:32:55 +13:00
Félix Saparelli e33fd8f5b5
Remove borrowing that was introduced in previous release 2019-10-28 22:32:08 +13:00
Félix Saparelli 05c0d4aaea
Allow clippy failures 2019-10-28 20:00:47 +13:00
Félix Saparelli a0053ccda4
1.11.0 2019-10-28 19:20:10 +13:00
Félix Saparelli 97fd7c6a17
Update nix, glob, env_logger 2019-10-28 19:02:57 +13:00
Félix Saparelli bb02d84661
Re-export useful things 2019-10-28 18:56:06 +13:00
Félix Saparelli 6c653e8e52
Return owned Args from Handler instead of borrowed 2019-10-28 18:55:39 +13:00
Wayne Warren 720ff44b71 #133: leave Handler initialization to watch caller 2019-10-28 18:17:25 +13:00
Félix Saparelli 31b5cb0ab6
Add chocolatey package 2019-10-28 14:51:04 +13:00
Félix Saparelli a1fbad0180
Fix last clippy lints 2019-10-28 13:48:57 +13:00
Félix Saparelli 7ef9d13b51
Fix travis clippy check 2019-10-28 13:19:12 +13:00
Félix Saparelli 2d4e74ef33
Fix travis msrv windows check 2019-10-28 13:18:09 +13:00
Félix Saparelli 544d133520
Adjust badges 2019-10-28 13:17:15 +13:00
Félix Saparelli e0a67e3e7e
Lint travis config 2019-10-28 13:13:09 +13:00
Félix Saparelli e54b7f2427
Remove appveyor 2019-10-28 13:11:33 +13:00
Félix Saparelli 24204e7b71
Add windows travis builds 2019-10-28 13:01:55 +13:00
Félix Saparelli f7e1639ed1
Upgrade to winapi 0.3 2019-10-28 12:17:00 +13:00
Félix Saparelli e563ae8fc1
Enable anti-unwrap lints 2019-10-28 01:12:10 +13:00
Félix Saparelli 5f7123ecbe
Lint tests too 2019-10-28 00:37:24 +13:00
Félix Saparelli a3c5bd7201
Run formatter 2019-10-28 00:31:52 +13:00
Félix Saparelli 10fac30c7b
Add editorconfig 2019-10-28 00:31:41 +13:00
Félix Saparelli d47419e385
Forbid a whole lot more clippy stuff 2019-10-28 00:31:26 +13:00
Félix Saparelli b842c149b6
Use Rust 2018 2019-10-27 23:58:00 +13:00
Félix Saparelli 0eb83a6387
Bump msrv to 1.38 2019-10-27 23:49:52 +13:00
Félix Saparelli f56e838fb9
Lints and clippys 2019-10-27 23:47:35 +13:00
Félix Saparelli 6b028cb649
Add builder for Args 2019-10-27 23:29:58 +13:00
Félix Saparelli 8e84eb6b04
Add semver policy statement 2019-10-27 22:54:44 +13:00
Sven-Hendrik Haase 3766114f40 Add zsh completions to release files 2019-10-23 17:29:44 +13:00
Sven-Hendrik Haase 63c7895407 Add --no-ignore to zsh completion 2019-10-23 17:29:44 +13:00
Sven-Hendrik Haase 43aa0947dc Add zsh completions for #118 (credit @Mange) 2019-10-23 17:29:44 +13:00
Sven-Hendrik Haase 7eafb48aa8 Prefer using --locked
This is to ensure that binaries built in this way are built reproducibly.
2019-10-23 17:28:54 +13:00
Josh Soref 0d4a2270ec spelling: supporting 2019-10-14 11:09:51 +13:00
Ryan James Spencer e90bbcb9bd Support a dedicated ignore file
ref. https://github.com/passcod/cargo-watch/issues/127

This adds support for a dedicated ignore file by the name of `.ignore` a
la `fd`, `ripgrep`, et. al.

This purely just mimics what `Gitignore` is doing except it doesn't
ignore `.git` directories. There might be more I need to tweak and the
interface might be too obtuse, but this is a first pass.

I've also added a `--no-ignore` flag which ignores both `.gitignore` and
the dedicated `.ignore`. It might make sense to add a specific flag that
ignores `.ignore` but respects `.gitignore` to support the old
behaviour, but I wasn't sure what to name it.
2019-10-12 14:13:57 +13:00
Jon Grythe Stødle c4ac0c0cbb Fix typo in `-e` description 2019-10-11 11:41:11 +13:00
Félix Saparelli 1738f26161 1.10.3 2019-07-30 11:47:37 +12:00
Leon Barrett 841d72b669 Update options in man page
The options were out of date (e.g. `-d` was debug). This updates them to
match the help text.

This also adds some documentation about separating the command with --
so that clap doesn't eat the flags intended for the command.
2019-07-30 11:44:58 +12:00
Félix Saparelli 64c7b5112e
Update Arch install instructions (close #107) 2019-06-20 15:46:39 +12:00
Félix Saparelli 0a2bc01c2f 1.10.2 2019-05-29 18:38:35 +12:00
Félix Saparelli 98b57ac64e [libs] Update notify to 4.0.12 2019-05-29 18:27:11 +12:00
Félix Saparelli 8e8410e35d [docs] Add zsh completion wiki page 2019-04-17 22:16:35 +12:00
Igor Gnatenko e59ca38c4f [meta] Exclude unneeded files from crates.io (#117) 2019-03-23 17:01:19 +13:00
Igor Gnatenko f91e23aa18 [libs] Update nix to 0.13 (#116) 2019-03-22 23:02:39 +13:00
Igor Gnatenko 22f5408bc0 Drop mktemp dependency (#115)
It is not used and depends on very very old version of uuid.

Signed-off-by: Igor Gnatenko <i.gnatenko.brain@gmail.com>
2019-03-12 00:49:17 +13:00
SpiralP dbc52e012e [run] Always canonicalize input paths (#113)
A client may pass non-canonicalized paths into `watch`, and these are therefore not matched against the filters correctly. Thus, some events could call a Handler's `on_update` method even when an ignored file was changed.

See repro: https://github.com/SpiralP/rust-cargo-watch-test

This bug was introduced in aae5a216b0.
2019-03-04 11:40:35 +13:00
Félix Saparelli 867ef7bc3c 1.10.1 2019-02-18 21:27:57 +13:00
Félix Saparelli 4918b123d9 [run] Restore clearing of the screen on initial run 2019-02-18 21:26:21 +13:00
Josh Gao 6342f86c10 [errors] Fix infinite recursion in fmt::Display for Error (#111) 2019-02-15 17:02:07 +13:00
Félix Saparelli 8eb90738de [run] Move "once" logic to be entirely within handler 2019-01-27 15:51:49 +13:00
Félix Saparelli 4ceb70f6bf [docs] Fix logic inversion in on_manual doc comment 2019-01-27 10:24:24 +13:00
Félix Saparelli b5afcd58ae 1.10.0 2019-01-26 18:21:52 +13:00
Félix Saparelli 8ffe20d545 [libs] Update other deps 2019-01-26 18:19:57 +13:00
Félix Saparelli 63afc013c9 [libs] Update Notify 2019-01-26 18:02:27 +13:00
Félix Saparelli 578ffa1deb [run] Fix outdated comment in ExecHandler 2019-01-26 17:42:36 +13:00
Félix Saparelli 5846b64020 [run] Further dry the ExecHandler 2019-01-26 17:32:48 +13:00
Félix Saparelli 3dd2f797ab [process] Remove some more unwrap 2019-01-26 17:26:33 +13:00
Félix Saparelli 6a23f77687 [run] Pass ops by reference when possible 2019-01-26 17:20:29 +13:00
Félix Saparelli ede5505a6b [run] Dry spawning the child process 2019-01-26 17:16:07 +13:00
Félix Saparelli 5e44cafb94 [windows] Attempt to use tput to clear the screen
In some situations, this may clear the screen better than a call to
`cls`, and in all other cases `cls` is called anyway.

May help #99
2019-01-26 15:22:09 +13:00
Félix Saparelli 6f473bcd87 [meta] Run formatter 2019-01-26 15:15:27 +13:00
Félix Saparelli 3a6c6b36b2
Merge pull request #105 from watchexec/c-bindings
Library changes for #103, building on #104
2019-01-26 15:09:39 +13:00
Félix Saparelli aae5a216b0 [api] Make watchexec take a Handler rather than a callback
Instead of special-casing the callback, which is the path least-taken,
switch the internals to a Handler model, where the default behaviour is
an implementation of a Handler, and external callers can implement their
own Handlers and pass them in.

While doing so, change all unwraps in run::run to returning Errs, and
expand the watchexec Error enum to accommodate. That should make it
easier to use as a library.

Also, differentiate between "manual" and "on update" runs. For now the
only manual run is the initial run, but this paves the way for e.g.
keyboard- or signal- triggered runs.
2019-01-26 14:45:13 +13:00
Félix Saparelli ac3a4f0717 [pathop] Revert changes adding a time field 2019-01-26 14:40:30 +13:00
Félix Saparelli b49bf74dd6 [meta] Revert .gitignore change 2019-01-26 09:16:43 +13:00
Félix Saparelli 65db0dfae1 [meta] Revert version bump 2019-01-26 09:16:02 +13:00
David Ziegler 7b3daeef9c Major changes for c bindings integration as third party crate (see project: github/InfinityMod/watchexec_c).
Changed version to 1.9.3 for third party crate compatibility detection.
2019-01-23 18:56:09 +01:00
Félix Saparelli 62d24168d6
Merge pull request #102 from Mange/fix-tty-output
Support running commands that allocate their own TTYs (*nix)
2019-01-19 18:48:43 +13:00
Magnus Bergmark 9fd25dd667
Use setsid() instead of setpgid()
This makes it possible to run commands that allocates TTYs and still
capture their output and reap the process on completion.

> setpgid — set process group ID for job control
> setsid — create session and set process group ID

With this in place, the `waitpid` call detects that the process has
exited even if the process allocated a TTY, and is able to unblock the
runner and continue.

Further, the output of the command is also shown in the controlling
terminal.
2019-01-17 13:21:27 +01:00
Félix Saparelli e0f649d79a Update clap version out of lock file, fixes #76 2018-12-15 14:24:43 +13:00
Félix Saparelli f6b16813aa Cfg off remaining items for a clean win/mac build
Closes #98
2018-10-05 20:56:06 +13:00
Félix Saparelli cee1712c4f Link up glob syntax documentation 2018-09-29 13:40:06 +12:00
Félix Saparelli ba23ed09f6 Fix tests 2018-09-09 16:16:40 +12:00
Félix Saparelli dc712197c0 1.9.2: revert whitespace changes 2018-09-09 16:03:01 +12:00
Félix Saparelli 0cc3110c7d 1.9.1 2018-09-09 15:01:18 +12:00
Félix Saparelli 4d283313fa Also build deb package 2018-09-09 15:00:51 +12:00
Félix Saparelli 3c1eaa51f7 Add missing impl for StdError 2018-09-09 10:38:07 +12:00
Félix Saparelli 9e09c98f96 Update earliest rust version 2018-09-09 00:03:30 +12:00
Félix Saparelli 2c5c145042 Extract errors into one thing and return a result more often 2018-09-08 23:51:44 +12:00
Félix Saparelli a6163cc599 Formatting 2018-09-08 20:08:36 +12:00
Félix Saparelli 9c60148b66
Merge pull request #95 from watchexec/wrap-whitespace-in-args
Wrap whitespace and quotes in command arguments
2018-09-08 19:44:39 +12:00
Félix Saparelli 5461c6ff1b
Merge pull request #74 from jaemk/fix_panic
don't panic on missing folder
2018-09-08 19:43:44 +12:00
Félix Saparelli 718647e386
Merge branch 'master' into fix_panic 2018-09-08 19:43:20 +12:00
Félix Saparelli 68c4973c09
Merge pull request #96 from sumnerevans/patch-1
Added installation instructions for Arch Linux
2018-09-04 10:24:53 +12:00
Sumner Evans 3288c1fad3
Added installation instructions for Arch Linux
watchexec is in the Arch User Repository (AUR). This adds instructions for installing on Arch Linux via the AUR.
2018-09-03 14:08:55 -06:00
Félix Saparelli 7375db5ce9 Also wrap when there’s quotes but no whitespace 2018-08-22 08:17:36 +12:00
Félix Saparelli 21d4080183 Wrap whitespace in arguments
Fixes #82
Fixes #87
2018-08-22 07:15:20 +12:00
Félix Saparelli 39a4a52f80 Restore 1.20 compatibility 2018-08-22 07:14:55 +12:00
Félix Saparelli ef0e6df8d4 Remove duplication between main/lib files 2018-08-22 00:10:57 +12:00
Félix Saparelli 88297f7866 Avoid impossible deploy situation with appveyor 2018-08-21 18:44:00 +12:00
Félix Saparelli 3069f4bb83 Install rustup target for musl 2018-08-21 16:28:42 +12:00
Félix Saparelli 2ac3c2ec5d Enable musl targets on linux (closes #89) 2018-08-21 16:06:58 +12:00
Félix Saparelli c73b57bcc2 Increase compression level for releases 2018-08-21 15:57:35 +12:00
Félix Saparelli 0480c1f645 Enable travis fast finish 2018-08-21 15:25:43 +12:00
Félix Saparelli 0bb32d5c49 Update minimum version 2018-08-21 15:18:13 +12:00
Félix Saparelli 3842d8c224 Adjust CI 2018-08-21 15:12:00 +12:00
Félix Saparelli f5d8d134a0 1.9.0 2018-08-19 21:31:46 +12:00
Félix Saparelli c7f7e18e3b Update man page with WATCHEXEC_*_PATH modifications from #90 2018-08-19 21:14:42 +12:00
Félix Saparelli f61b7507af Update dependencies 2018-08-19 20:58:47 +12:00
Félix Saparelli 83a3e3b085
Merge pull request #90 from Calinou/update-env-variable-documentation
Update the environment variable documentation in README
2018-08-19 20:45:11 +12:00
Félix Saparelli 750dcb197d
Merge pull request #91 from rasa/patch-1
Add scoop installation instructions to readme
2018-08-19 20:32:47 +12:00
Félix Saparelli 31fdca564a
Merge pull request #93 from tailhook/max_user_watches
Add a warning and fallback on polling mode if limit exceeded
2018-08-19 20:29:44 +12:00
Félix Saparelli 93bd1d9881
Merge pull request #77 from bruceg/master
Fix some default ignore pattern issues
2018-08-19 20:23:49 +12:00
Félix Saparelli 5d58a657ee
Merge pull request #92 from bugabinga/master
Bumps __nix__ to __0.11.0__ in order to support OpenBSD 6.3+.
2018-08-19 20:22:50 +12:00
Paul Colomiets a2d0a251da Add a warning and fallback on polling mode if limit exceeded
Works only on linux (not sure how error is named on other systems):
```
*** System notification limit is too small, falling back to polling
mode.
*** For better performance increase system limit:
   sysctl fs.inotify.max_user_watches=524288
*** Polling for changes every 1000 ms
```

Fixes #62
2018-08-02 19:36:50 +03:00
Oliver Jan Krylow 8de93a8fd2
Bumps __nix__ to __0.11.0__ in order to support OpenBSD 6.3+. 2018-07-30 21:20:12 +02:00
Ross Smith II b59eda30dd
Add scoop installation instructions to readme 2018-07-23 21:15:16 -07:00
Hugo Locurcio a9de2cde44
Update the environment variable documentation in README
This makes the documentation reflect changes from commit 8bd9bb3.
2018-07-23 15:33:47 +02:00
Bruce Guenter 1d8d6595e0 Add .pyo to the Python temporary file ignore
Python, when invoked with the -O option, writes compiled code to .pyo
files instead of .pyc. Add this to the default ignores list.
2018-02-08 14:53:12 -06:00
Bruce Guenter 422546b175 Add Emacs temporary files to the default ignored list
Emacs generates temporary backup files while editing named "#FILENAME#"
and ".#FILENAME". Ignore these by default.
2018-02-08 14:53:11 -06:00
Bruce Guenter c98bea3118 Fix default ignore for vim temporary files
.swp files are created by vim to store editing state while a file is
open. However, it may also create .swo, .swn, etc files if .swp already
exists. Also, the temporary files are always hidden (start with ".").
Finally, vim temporarily creates .swpx files as well which are caught by
inotify.

This change fixes the *.swp pattern to only match hidden files and to
match the other vim temporary files.
2018-02-08 14:53:08 -06:00
James Kominick 31b5e56959 don't panic on missing folder
issue #71
- Add some basic error handling
- Convert missing folder panic to error
2017-12-13 23:10:12 -05:00
Matt Green b9822266db
Merge pull request #73 from mcgoo/master
fix screen clearing on windows
2017-12-06 15:38:25 -05:00
Jim McGrath 9b4e74ed30 fix screen clearing on windows 2017-12-06 11:40:04 -06:00
Matt Green 1456fa2ee9
Merge pull request #72 from jmgao/master
Use `tput reset` to clear screen.
2017-11-30 12:39:33 -05:00
Josh Gao 76d959b27b Use `tput reset` to clear screen.
Use `tput reset` instead of `clear` so that scrollback is cleared in
addition to the currently visible portion of the terminal.
2017-11-21 00:55:58 -05:00
Matt Green 9f82872943 1.8.6 2017-10-09 08:56:55 -04:00
Matt Green 3de894e07c Merge pull request #70 from mattgathu/fix_clippy_warnings_run
fix (src/run.rs): fixed cargo clippy warnings
2017-10-09 08:54:41 -04:00
Matt Green b035cbf44a Merge pull request #69 from mattgathu/fix_clippy_warnings_process
fix (src/process.rs): fix cargo clippy linter warnings
2017-10-09 08:53:55 -04:00
Matt Green 8770ae3967 Handle relative ignores better? 2017-10-07 15:50:47 -04:00
Matt Gathu 8509cbfd77
fix (src/run.rs): fixed cargo clippy warnings
This addresses warnings reported by cargo clippy on `src/run.rs`:

* warning: this expression borrows a reference that is immediately dereferenced by the compiler

reference:
- https://rust-lang-nursery.github.io/rust-clippy/v0.0.165/index.html#needless_borrow
- https://github.com/rust-lang-nursery/rust-clippy
2017-10-06 14:31:36 +03:00
Matt Gathu 775eb47dde
fix (src/process.rs): fix cargo clippy linter warnings
This PR fixes lint warnings generated by cargo-clippy:

- **warning**: you should put `notify::ops::RENAME` between ticks in the documentation
- **warning**: use of `or_insert` followed by a function call

I have run `cargo test` and these changes do not break any of the tests :-)

reference:
--

* https://rust-lang-nursery.github.io/rust-clippy/v0.0.165/index.html#doc_markdown
* https://rust-lang-nursery.github.io/rust-clippy/v0.0.165/index.html#or_fun_call
* https://github.com/rust-lang-nursery/rust-clippy
2017-10-06 13:55:21 +03:00
Matt Green 93b7b0343f Pin clap dep, closes #61 2017-09-14 19:25:55 -04:00
Matt Green 589cd224b4 Merge pull request #65 from jaemk/update_details
update details
2017-09-14 19:24:45 -04:00
James Kominick 8bd9bb3c25 detailed update information
issue #59
- Keep track of `notify::op::Op`s associated with each updated path
- Collect paths into `notify::op::Op` categories and pass them on as
  environment vars
- Set a COMMON_PATH and use relative paths if more than one unique
  path was touched
2017-09-09 13:55:44 -04:00
Matt Green d6ea55cbd4 1.8.5 2017-09-08 16:17:52 -04:00
Matt Green 06fd2954dd Merge pull request #64 from jaemk/configurable_debounce
Add `-d, --debounce` option
2017-09-08 16:16:19 -04:00
James Kominick 0e34123023 Add `-d, --debounce` option
- Add configurable debounce timeout option behind `-d, --debounce`
- Move `-d, --debug` flags to `-v, --verbose`
2017-09-07 19:44:57 -04:00
Matt Green a7860116f7 Merge pull request #63 from lilianmoraru/master
Update dependencies and other small improvements
2017-09-06 09:46:14 -04:00
Lilian A. Moraru e39256cfb2 Update dependencies and other small improvements 2017-08-26 22:07:06 +03:00
Matt Green 7b76d3d268 Merge pull request #60 from octaltree/fix-conflicted-doc
Resolving conflicted cargo documents
2017-06-03 09:55:38 -04:00
octaltree 8b66298bae add [[bin]] doc = false 2017-06-03 12:16:45 +09:00
Matt Green e3105c0abb Bump to 1.8.4 2017-05-18 13:23:24 -04:00
Matt Green 3fc501c4f0 Windows: fix waiting for job to finish; closes #55 2017-05-18 13:22:46 -04:00
Matt Green db39d75f51 Fix build requirements in README, closes #57 2017-05-15 17:10:59 -04:00
Matt Green 6ebb7bc7b3 Also ignore changes to ignored dirs themselves 2017-05-10 12:02:49 -04:00
Matt Green f4774d6f8c 1.8.3 2017-04-27 15:40:00 -04:00
Matt Green e6de016cb9 Ensure correct path separators are used for VCS ignore dirs 2017-04-27 15:39:12 -04:00
Matt Green f9a3cade26 Add common VCS dirs to default ignore list (fixes #54) 2017-04-27 15:20:44 -04:00
Matt Green 0696b5266b 1.8.1 2017-04-26 10:13:02 -04:00
Matt Green a63006bc44 Merge pull request #53 from akerl/feature/no-default-ignore
Add no-default-ignore option, fixes #45
2017-04-26 09:20:33 -04:00
Les Aker 58ff772d62 add docs for no-default-ignore 2017-04-25 21:17:46 -04:00
Les Aker 356dac189d add no-default-ignore option, fixes #45 2017-04-25 21:17:45 -04:00
Matt Green fe0d5243bd Remove /.* ignore pattern (see #45) 2017-04-25 16:48:44 -04:00
Matt Green d64ced0250 Merge pull request #52 from passcod/library-interface
Add a library interface
2017-04-25 15:53:05 -04:00
Félix Saparelli 158d0dc9c4
Update to clap 2.22 2017-04-25 11:42:47 +12:00
Félix Saparelli f5bf4ef98b
Add library interface 2017-04-25 11:31:50 +12:00
Matt Green f3093faf97 1.8.0 2017-04-19 17:34:46 -04:00
Matt Green 912ed136f1 Note that Rust 1.15 is required 2017-04-17 12:52:46 -04:00
Matt Green eea9428f41 Merge pull request #48 from chr4/no_shell
Add support for --no-shell option
2017-04-12 11:17:42 -04:00
Chris Aumann f88f1b36c3 Refactor command assembly
Kudos to https://www.reddit.com/user/burntsushi from the /r/rust community!
See: https://www.reddit.com/r/rust/comments/64ic0q/idiomatic_string_processing/
2017-04-10 14:13:27 +02:00
Chris Aumann a395ed84cd Remove useless format!()
This was a hint by `cargo clippy`
2017-04-10 00:20:57 +02:00
Chris Aumann df72aaf977 Use if-else statements instead of boolean match
This was a hint by `cargo clippy`
2017-04-10 00:20:57 +02:00
Chris Aumann 780b54b34e Port --no-shell to Windows 2017-04-10 00:20:57 +02:00
Chris Aumann 5a7ccf759b Adapt spawn() test for Unix 2017-04-10 00:20:27 +02:00
Chris Aumann ea130dd021 Add documentation for --no-shell 2017-04-10 00:20:27 +02:00
Chris Aumann ee5e93e6af Add support for --no-shell option 2017-04-10 00:19:58 +02:00
Matt Green 5d5bc4f17b Merge pull request #49 from chr4/minor_typo_fixes
Minor typo fixes
2017-04-09 17:10:30 -04:00
Chris Aumann 5b486e2ae6 Remove deprecated comment (before_exec) 2017-04-06 22:54:02 +02:00
Chris Aumann e509ed0b18 Remove unnecessary space from watchexec.1.html 2017-04-06 22:53:14 +02:00
Matt Green 00a339a2f1 Merge pull request #43 from chr4/signal_flag
Signal flag
2017-04-03 12:04:52 -04:00
Chris Aumann 264ec282d6 Use a tuple to match scenarios 2017-04-02 21:28:00 +02:00
Chris Aumann 4763de3790 Re-add --kill flag for compatibility
--kill translates to --signal SIGKILL
2017-04-02 21:21:30 +02:00
Chris Aumann 627f828b3c Rename wait_process() to signal_process() 2017-04-02 21:21:30 +02:00
Chris Aumann f5f65c3a28 Add --signal documentation to doc/* 2017-04-02 21:21:30 +02:00
Chris Aumann d5da94fcaf Add check for conflicting --signal and --postpone arguments 2017-04-02 21:21:30 +02:00
Chris Aumann 14941c89d2 Add SIGHUP example to README 2017-04-02 21:21:30 +02:00
Chris Aumann c98d0e6cfd Decouple --restart and --signal, so they both make sense
This change takes account of the following four use cases:

1. Make sure the previous run was ended, then run the command again (default)
2. Just send a specified signal to the child, do nothing more (--signal given)
3. Send SIGTERM to the child, wait for it to exit, then run the command again (--restart given)
4. Send a specified signal to the child, wait for it to exit, then run the command again (--restart and --signal given)
2017-04-02 21:21:30 +02:00
Chris Aumann 56ddfcbaee Apply rustfmt-0.8.1 2017-04-02 21:21:30 +02:00
Chris Aumann 3a5ff290d5 Use a more idiomatic way to set --signal 2017-04-02 21:19:53 +02:00
Chris Aumann debfafb47b Adapt README to --signal option 2017-04-02 21:19:53 +02:00
Chris Aumann a2f6b0013f Add windows compatibility 2017-04-02 21:19:53 +02:00
Chris Aumann 0a445c9f76 Move convert_to_libc() method to signal.rs 2017-04-02 21:19:53 +02:00
Chris Aumann 4adde457dd Actually use signal specified in --signal option 2017-04-02 21:19:53 +02:00
Chris Aumann 382981e22d Add more signals to SigSet mask 2017-04-02 21:19:53 +02:00
Chris Aumann eebe966b50 Remove deprecated signal functions 2017-04-02 21:19:53 +02:00
Chris Aumann 24e9b0c1c5 Migrate to nix::sys::signal::Signal 2017-04-02 21:19:52 +02:00
Chris Aumann 68caf04269 First commit to add a generic --signal flag 2017-04-02 21:19:52 +02:00
Matt Green ffc68fb4df Merge pull request #44 from chr4/before_exec
Use before_exec as process_exec landed in stable
2017-03-31 12:31:53 -04:00
Matt Green 0cd2a8f037 Merge pull request #46 from ootoovak/patch-1
Fix headers in Readme file.
2017-03-31 12:26:43 -04:00
Samson Ootoovak ee5f7509b5 Fix headers in Readme file.
Just added spaces so the markdown recognises the headers.
2017-03-27 21:56:06 +13:00
Chris Aumann f62c3724b2 Use before_exec as process_exec landed in stable 2017-03-24 17:11:24 +01:00
Matt Green 4fffb534b6 Fix atrocious spacing in Makefile 2017-02-07 10:30:47 -05:00
Matt Green 9e68f0c063 Add Homebrew + Cargo targets 2017-02-06 18:15:51 -05:00
Matt Green 0e371d1c56 Update docs for 1.7.0 2017-02-05 13:29:38 -05:00
Matt Green 5427f9fe93 Add category 2017-02-05 13:18:22 -05:00
Matt Green 125e7eb7c8 rustfmt & clippy fixes 2017-02-04 16:26:59 -05:00
Matt Green e16a6b3a24 Support watching multiple paths 2017-02-04 16:18:02 -05:00
Matt Green cd083ef650 Bump to 1.7.0 2017-02-04 14:54:14 -05:00
Matt Green 53c1f39919 Load + handle multiple .gitignore files in project dir 2017-02-04 14:53:27 -05:00
Matt Green b2b0a60ca5 Add -1 option for integration testing, closes #35 2017-01-27 15:27:44 -05:00
Matt Green 0d5de7c4da rustfmt 2017-01-27 13:13:37 -05:00
Matt Green c3e7cf00d5 cargo update 2017-01-27 13:13:08 -05:00
Matt Green ebcb5976ba Use globset for ignore matching; closes #14 and #23 2017-01-27 13:00:13 -05:00
Matt Green ed474ccfe3 Update Homebrew instructions 2017-01-19 11:35:38 -05:00
Matt Green fd2d6e364a Add -k to support sending SIGKILL 2017-01-16 14:18:38 -05:00
Matt Green 6b7351d45b Remove kill/wait tests as process handling is async now 2016-12-20 13:42:39 -05:00
Matt Green dddc1e8886 Fix Windows warnings 2016-12-20 13:25:08 -05:00
Matt Green 09448cd91e Fix reap() hanging when child processes are still running 2016-12-20 13:21:24 -05:00
Matt Green 171132a722 rustfmt & clippy fixes 2016-12-20 12:20:21 -05:00
Matt Green 2dd2e72214 Update dependencies 2016-12-20 11:48:45 -05:00
Matt Green b2c809c87a SIGCHLD handling 2016-12-20 11:44:18 -05:00
Matt Green a925cb356a Fix sending SIGKILL by default when restarting processes 2016-12-19 15:36:59 -05:00
Matt Green 9c65e816da Add -k option to send SIGKILL instead of SIGTERM; closes #31 2016-12-19 11:37:20 -05:00
Matt Green 787c31040c Remask received signal after re-raising it 2016-12-15 09:41:10 -05:00
Matt Green 154c23a5a4 Propagate SIGTSTP/SIGCONT to children 2016-12-14 20:19:58 -05:00
Matt Green ef37a9fb97 Add example that uses --; closes #28 2016-12-14 19:45:31 -05:00
Matt Green 8797b35926 Update README 2016-11-23 13:11:25 -05:00
Matt Green ceda4a553c 1.5.0 2016-11-23 13:01:51 -05:00
Matt Green 54baf4e384 Add process::spawn function 2016-11-23 12:59:56 -05:00
Matt Green 98c2698798 Document dropped --watch option 2016-11-17 08:49:31 -05:00
Matt Green f768721ca3 Remove --watch option, always watch cwd 2016-11-17 08:45:55 -05:00
Matt Green 0e9dafffc8 Unix: pipe read/write handles EINTR 2016-11-16 20:18:46 -05:00
Matt Green 12557d11bf Fix setpgid() racing killpg()/waitpid() in tests 2016-11-16 08:55:15 -05:00
Matt Green e4557e462b Wait for child process, not any child process in group 2016-11-15 22:43:51 -05:00
Matt Green 271ef84192 CI: Use stable channel on AppVeyor 2016-11-15 17:19:15 -05:00
Matt Green d80eb45d5a CI: try stable Rust release 2016-11-15 17:16:40 -05:00
Matt Green 5b2858e6d6 Die quietly if exec() fails 2016-11-15 17:04:15 -05:00
Matt Green 3bf3086a29 Replace before_exec with fork/exec, removing Rust nightly requirement 2016-11-15 16:55:29 -05:00
Matt Green bdce629782 Drop size optimizations that require nightly builds 2016-11-13 18:34:23 -05:00
Matt Green 0ef334e2a1 Size optimizations 2016-11-10 19:43:13 -05:00
Matt Green 68960fec9a Style fixes 2016-11-09 17:48:38 -05:00
Matt Green 48b0def80d Fix warnings in tests 2016-11-09 17:37:35 -05:00
Matt Green 2d2a8cb079 rustfmt 2016-11-09 17:25:52 -05:00
Matt Green 707fa2e952 Windows compilation fixes 2016-11-09 17:20:13 -05:00
Matt Green 6523f6edf5 Cleanup, initial Windows implementation of interrupt handler 2016-11-09 17:00:24 -05:00
Matt Green cf0a98b7a5 Remove use of select! 2016-11-09 09:44:00 -05:00
Matt Green 4d03519631 Update credits 2016-11-08 21:57:09 -05:00
Matt Green 060f301d55 Update brew formula 2016-11-08 21:53:13 -05:00
Matt Green 9f0c3cd3f8 1.4.0 2016-11-08 18:02:31 -05:00
Matt Green 0d85d8275a Fix gitignore searching not terminating in some cases; closes #25 2016-11-08 17:52:29 -05:00
Matt Green c416c6082c Merge pull request #26 from craftytrickster/greatest-common-path-refactor
Refactoring get_longest_common_path to be simpler and more efficient
2016-11-07 19:36:19 -05:00
David Raifaizen dfe9dcc338 Refactoring get_longest_common_path to be simpler and more efficient 2016-11-05 08:42:45 -04:00
Matt Green 370898562d Merge branch 'master' of github.com:mattgreen/watchexec 2016-11-03 18:29:39 -04:00
Matt Green a2e66f179c Upgrade to notify 3; closes #22 2016-11-03 17:20:43 -04:00
Matt Green 06bcef5853 Use globset in NotificationFilter; closes #24 2016-11-03 17:04:39 -04:00
Matt Green 1a028e5788 Add crates.io badge 2016-11-03 16:33:41 -04:00
Matt Green 9e5eef9c7f 1.3.0 2016-11-03 16:17:58 -04:00
Matt Green fb81b9d219 Update man page for 2016-10-30 13:58:59 -04:00
Matt Green 8f916c495f Apply clippy suggested fixes 2016-10-30 12:37:34 -04:00
Matt Green 69eedd4cc5 rustfmt fixes 2016-10-30 12:28:54 -04:00
Matt Green d859b4b70e Drop threadpool dep (was spawning threads over and over) 2016-10-30 12:28:11 -04:00
Matt Green 2d7715f8d7 Merge pull request #20 from craftytrickster/common-prefix
Creating method to update the watch_exec variable with the greatest c…
2016-10-30 10:06:40 -04:00
David Raifaizen 8713140a4e Creating method to update the watch_exec variable with the greatest common path found among the changed filepaths 2016-10-29 14:39:48 -04:00
Matt Green 3ed6906aa4 Package man page and LICENSE with executable 2016-10-29 13:16:31 -04:00
Matt Green 22bfb44868 Man page refinements 2016-10-29 13:12:48 -04:00
Matt Green 488188c6de Add man page 2016-10-29 13:08:55 -04:00
Matt Green 85f0a4aaaf Make --run-initially default, add --postpone flag to disable 2016-10-29 10:43:45 -04:00
Matt Green 9265b5eef9 1.2.3 2016-10-29 10:29:01 -04:00
Matt Green 82713fc906 Fix watching multiple dirs with differing roots 2016-10-29 10:24:31 -04:00
Matt Green 9652aeb837 Fix dotted dir default filter to only fire on dirs 2016-10-29 10:21:04 -04:00
Matt Green a182fda43f Add NotificationFilter tests 2016-10-29 09:37:50 -04:00
Matt Green 233c6abc09 Bump version 2016-10-28 09:14:06 -04:00
Matt Green ed865d9039 Linux: fix logspam from inotify's notification volume 2016-10-28 08:58:15 -04:00
Matt Green 672fd469a9 Reorder new() 2016-10-28 08:46:35 -04:00
Matt Green 4370d41e71 Make NotificationFilter immutable 2016-10-27 08:27:16 -04:00
Matt Green fdc31d4b02 Fix test 2016-10-26 16:29:34 -04:00
Matt Green 0631a98429 Add test target 2016-10-26 16:29:20 -04:00
Matt Green 72a448b6e4 Bump version 2016-10-26 16:23:18 -04:00
Matt Green e26eff226c Process module improvements, use later nix 2016-10-26 16:20:44 -04:00
Matt Green d14ccaaa1a Fix Windows warnings 2016-10-26 11:52:00 -04:00
Matt Green f04083a21d Use Process & ProcessReaper to handle async process waiting 2016-10-26 11:02:04 -04:00
Matt Green 1cc4d92345 PollWatcher sometimes reports directories with new/deleted files 2016-10-26 11:02:04 -04:00
Matt Green 35c1b5fe24 Merge pull request #18 from robinst/patch-1
README: Add rustup command for installing with nightly
2016-10-26 09:27:10 -04:00
Robin Stocker 52c5e9f4ce README: Add rustup command for installing with nightly
I had to figure out how to install watchexec with nightly using rustup.
A lot of people are probably not familiar with it, so include the commands.
2016-10-26 12:16:33 +11:00
Matt Green 542fdb91cb Update Homebrew formula 2016-10-25 07:50:41 -04:00
Matt Green da46e3ffb5 Fix unused import warnings 2016-10-25 07:27:07 -04:00
Matt Green f7771a4480 Mark process tests as Unix-only for now 2016-10-25 07:19:41 -04:00
Matt Green 50e583ca8c Some tests for the Runner module 2016-10-25 07:05:53 -04:00
Matt Green 3d3915844a Improve runner API 2016-10-25 05:47:53 -04:00
Matt Green 918fd668a5 Polishing up process group handling and handling of unresponsive child processes 2016-10-24 21:49:12 -04:00
Matt Green d01da72e0b Forgot a #[cfg(unix)] marker on install() 2016-10-24 09:55:00 -04:00
Matt Green 0e0d14b475 Wait for FS activity to stop before proceeding; use interrupt handling 2016-10-24 09:53:06 -04:00
Matt Green d10b790c35 Use rustfmt to fix outstanding style issues 2016-10-23 20:12:48 -04:00
Matt Green 6a812d31b4 Extract CLI arg handling to args module 2016-10-23 20:07:48 -04:00
Matt Green 7b766b1f98 Drop signal crate in favor of nix 2016-10-23 15:15:28 -04:00
Matt Green f0d4a14e41 Fix Windows bugs relating to mutability 2016-10-22 17:05:43 -04:00
Matt Green 83b91e51d0 Refactor Runner a bit; add Drop impl for eventual use 2016-10-22 16:54:16 -04:00
Matt Green a408975bdc Attempt fixing signal for Linux build 2016-10-22 16:12:28 -04:00
Matt Green e67751bb56 Fix build errors on Windows 2016-10-22 15:51:17 -04:00
Matt Green 865b0b7d90 WIP: Add interrupt_handler module 2016-10-22 15:37:03 -04:00
Matt Green 5b34a5590c Remove version from Homebrew formula 2016-10-20 17:37:36 -04:00
Matt Green 1582240dbc Fix silly error 2016-10-20 14:30:05 -04:00
Matt Green 7d8f909220 Add watcher module, back to requiring nightly builds 2016-10-20 14:27:11 -04:00
Matt Green 03775b61ce No need to use before_exec() to call setpgid() 2016-10-20 12:09:51 -04:00
Matt Green b16cbec3ee Fix compile error on Windows 2016-10-20 11:50:25 -04:00
Matt Green 8a6a540bb6 Use correct channel on AppVeyor 2016-10-20 11:45:25 -04:00
Matt Green 1f91654662 Require nightly Rust due to use of before_exec 2016-10-20 11:40:36 -04:00
Matt Green 532aed11bd Bump version to 1.2.0 2016-10-20 11:39:16 -04:00
Matt Green f3c6df8845 Launch child processes in new process group 2016-10-20 11:38:51 -04:00
Matt Green f0650274a0 Bump version to 1.1.1 2016-10-20 10:08:12 -04:00
Matt Green 0a08d3f8ef Fix polling always being used 2016-10-20 10:07:55 -04:00
Matt Green 8ed6ed60ea Update version to 1.1 2016-10-19 20:19:48 -04:00
Matt Green 90d6659141 Add --force-poll option; closes #7 2016-10-19 20:19:01 -04:00
Matt Green a75dd49114 Set $WATCHEXEC_UPDATED_PATH to first changed path in child process;
closes #11
2016-10-19 19:40:50 -04:00
Matt Green 249e5a84e4 Search for .gitignore files in parent dirs; closes #10 2016-10-19 18:54:20 -04:00
Matt Green f1597cc1a6 Merge pull request #13 from palfrey/12-run-initially
Option to run command initially, before first file change
2016-10-18 18:05:14 -04:00
Matt Green 2ceefe44db Merge pull request #9 from 4tm4j33tk4ur/clippy
some clippy-suggested improvements
2016-10-18 17:36:23 -04:00
Tom Parker 7eabee9f40 Initial command run is outside the loop! 2016-10-18 22:36:12 +01:00
Tom Parker 6887552aab Option to run command initially, before first file change (fixes #12) 2016-10-18 22:11:05 +01:00
Atmajeet Kaur f7c628c7e1 some clippy-suggested improvements 2016-10-18 15:39:40 +02:00
Matt Green dde7453a47 Add Cargo instructions; closes #8 2016-10-17 21:26:11 -04:00
Matt Green 22d98005fb Add package metadata 2016-10-17 21:26:11 -04:00
Matt Green fd435785aa Merge pull request #6 from neodc/patch-1
Fix inconsistency in README
2016-10-17 14:58:49 -04:00
Noé De Cuyper c4bbddc353 Fix inconsistency in README 2016-10-17 20:55:28 +02:00
Matt Green ff2ce68779 Merge pull request #5 from gsquire/cfg
Use cfg attributes
2016-10-17 14:28:19 -04:00
Garrett Squire 59724589ea use cfg attributes instead of macro for OS specific functionality 2016-10-17 10:35:15 -07:00
Matt Green 5cd6ee5a9b Add install instructions for non-macOS users 2016-10-17 11:53:43 -04:00
Matt Green 57efffb0f2 Add badges 2016-10-15 14:03:23 -04:00
Matt Green 09386a61b1 Update Homebrew formula 2016-10-15 11:15:11 -04:00
Matt Green ff7bb9bf45 Remove status section 2016-10-15 11:05:57 -04:00
Matt Green a68e911e87 Bump version to 1.0.0 2016-10-15 11:05:19 -04:00
Matt Green af885f32e5 Appveyor: build off of master 2016-10-15 11:03:48 -04:00
Matt Green b8e6672562 Bump to 0.12.0 2016-10-15 11:01:30 -04:00
Matt Green 4144abada4 Triggering appveyor to build 2016-10-15 10:47:35 -04:00
Matt Green 190b58a899 CI fun 2016-10-15 10:43:25 -04:00
Matt Green a7f56ef926 Update README a little for CI 2016-10-15 10:25:37 -04:00
Matt Green 5cf2e5d6fe Add appveyor.yml 2016-10-15 10:09:35 -04:00
Matt Green 542f2a85f5 Drop regex dep 2016-10-14 09:33:23 -04:00
Matt Green 7ea2b09fc5 Add Linux in there too 2016-10-14 07:53:45 -04:00
Matt Green 855e88f6e4 Use legit target for OS X 2016-10-14 07:40:26 -04:00
Matt Green 03c5096f31 Add CI scripts 2016-10-13 22:09:34 -04:00
Matt Green 1f5c76d194 Add deploy section 2016-10-13 21:32:15 -04:00
Matt Green 6541e51288 Poking travis to build 2016-10-13 20:41:21 -04:00
Matt Green dc9842312e Begin travis integration 2016-10-13 20:34:47 -04:00
Matt Green a72bc099dc Cargo.lock should be committed for apps 2016-10-13 20:26:32 -04:00
Matt Green 94311c25bb Ignore .DS_Store files by default 2016-10-13 20:23:38 -04:00
Matt Green 536613852f Enhance debug output; rename option back to debug 2016-10-13 20:21:29 -04:00
Matt Green 392aea8ca3 Use crate_version! macro 2016-10-13 19:57:21 -04:00
Matt Green b6831c4d30 Cleanups/more logging 2016-10-13 19:47:04 -04:00
Matt Green 8923bc1e1c Use log & env_logger crates 2016-10-13 17:59:46 -04:00
Matt Green 20fe9169b4 Add --no-vcs-ignore flag 2016-10-12 09:43:22 -04:00
Matt Green 3b2e55855f Update status 2016-10-12 09:30:40 -04:00
Matt Green 9893b5964f Update Homebrew formula 2016-10-12 09:29:44 -04:00
227 changed files with 29706 additions and 742 deletions

11
.cargo/config Normal file
View File

@ -0,0 +1,11 @@
[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
[target.armv7-unknown-linux-musleabihf]
linker = "arm-linux-musleabihf-gcc"
[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"

12
.clippy-lints Normal file
View File

@ -0,0 +1,12 @@
-W clippy::nursery
-W clippy::pedantic
-A clippy::module-name-repetitions
-A clippy::similar-names
-A clippy::cognitive-complexity
-A clippy::too-many-lines
-A clippy::missing-errors-doc
-A clippy::missing-panics-doc
-A clippy::default-trait-access
-A clippy::enum-glob-use
-A clippy::option-if-let-else
-A clippy::blocks-in-conditions

21
.editorconfig Normal file
View File

@ -0,0 +1,21 @@
root = true
[*]
indent_style = tab
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[cli/tests/snapshots/*]
indent_style = space
trim_trailing_whitespace = false
[*.{md,ronn}]
indent_style = space
indent_size = 4
[*.{cff,yml}]
indent_size = 2
indent_style = space

3
.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
Cargo.lock merge=binary
doc/watchexec.* merge=binary
completions/* merge=binary

17
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,17 @@
---
name: Bug report
about: Something is wrong
title: ''
labels: bug, need-info
assignees: ''
---
Please delete this template text before filing, but you _need_ to include the following:
- Watchexec's version
- The OS you're using
- A log with `-vvv --log-file` (if it has sensitive info you can email it at felix@passcod.name — do that _after_ filing so you can reference the issue ID)
- A sample command that you've run that has the issue
Thank you

View File

@ -0,0 +1,24 @@
---
name: Feature request
about: Something is missing
title: ''
labels: feature
assignees: ''
---
<!-- Please note that this project has a high threshold for changing default behaviour or breaking compatibility. If your feature or change can be done without breaking, present it that way. -->
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
If proposing a new CLI option, option names you think would fit.
**Additional context**
Add any other context about the feature request here.

23
.github/ISSUE_TEMPLATE/regression.md vendored Normal file
View File

@ -0,0 +1,23 @@
---
name: Regression
about: Something changed unexpectedly
title: ''
labels: ''
assignees: ''
---
**What used to happen**
**What happens now**
**Details**
- Latest version that worked:
- Earliest version that doesn't: (don't sweat testing earlier versions if you don't remember or have time, your current version will do)
- OS:
- A debug log with `-vvv --log-file`:
```
```
<!-- You may truncate the log to just the part supporting your report if you're confident the rest is irrelevant. If it contains sensitive information (if you can't reduce/reproduce outside of work you'd rather remain private, you can either redact it or send it by email.) -->

50
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,50 @@
# Dependabot dependency version checks / updates
version: 2
updates:
- package-ecosystem: "github-actions"
# Workflow files stored in the
# default location of `.github/workflows`
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/cli"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/lib"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/events"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/signals"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/supervisor"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/filterer/ignore"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/filterer/globset"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/bosion"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/ignore-files"
schedule:
interval: "weekly"
- package-ecosystem: "cargo"
directory: "/crates/project-origins"
schedule:
interval: "weekly"

62
.github/workflows/clippy.yml vendored Normal file
View File

@ -0,0 +1,62 @@
name: Clippy
on:
workflow_dispatch:
pull_request:
push:
branches:
- main
tags-ignore:
- "*"
env:
CARGO_TERM_COLOR: always
CARGO_UNSTABLE_SPARSE_REGISTRY: "true"
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
jobs:
clippy:
strategy:
fail-fast: false
matrix:
platform:
- ubuntu
- windows
- macos
name: Clippy on ${{ matrix.platform }}
runs-on: "${{ matrix.platform }}-latest"
steps:
- uses: actions/checkout@v4
- name: Configure toolchain
run: |
rustup toolchain install stable --profile minimal --no-self-update --component clippy
rustup default stable
# https://github.com/actions/cache/issues/752
- if: ${{ runner.os == 'Windows' }}
name: Use GNU tar
shell: cmd
run: |
echo "Adding GNU tar to PATH"
echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%"
- name: Configure caching
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Clippy
run: cargo clippy -- $(cat .clippy-lints | tr -d '\r' | xargs)
shell: bash

26
.github/workflows/dist-manifest.jq vendored Normal file
View File

@ -0,0 +1,26 @@
{
dist_version: "0.0.2",
releases: [{
app_name: "watchexec",
app_version: $version,
changelog_title: "CLI \($version)",
artifacts: [ $files | split("\n") | .[] | {
name: .,
kind: (if (. | test("[.](deb|rpm)$")) then "installer" else "executable-zip" end),
target_triples: (. | [capture("watchexec-[^-]+-(?<target>[^.]+)[.].+").target]),
assets: ([[
{
kind: "executable",
name: (if (. | test("windows")) then "watchexec.exe" else "watchexec" end),
path: "\(
capture("(?<dir>watchexec-[^-]+-[^.]+)[.].+").dir
)\(
if (. | test("windows")) then "\\watchexec.exe" else "/watchexec" end
)",
},
(if (. | test("[.](deb|rpm)$")) then null else {kind: "readme", name: "README.md"} end),
(if (. | test("[.](deb|rpm)$")) then null else {kind: "license", name: "LICENSE"} end)
][] | select(. != null)])
} ]
}]
}

325
.github/workflows/release-cli.yml vendored Normal file
View File

@ -0,0 +1,325 @@
name: CLI Release
on:
workflow_dispatch:
push:
tags:
- "v*.*.*"
env:
CARGO_TERM_COLOR: always
CARGO_UNSTABLE_SPARSE_REGISTRY: "true"
jobs:
info:
name: Gather info
runs-on: ubuntu-latest
outputs:
cli_version: ${{ steps.version.outputs.cli_version }}
steps:
- uses: actions/checkout@v4
- name: Extract version
id: version
shell: bash
run: |
set -euxo pipefail
version=$(grep -m1 -F 'version =' crates/cli/Cargo.toml | cut -d\" -f2)
if [[ -z "$version" ]]; then
echo "Error: no version :("
exit 1
fi
echo "cli_version=$version" >> $GITHUB_OUTPUT
build:
strategy:
matrix:
name:
- linux-amd64-gnu
- linux-amd64-musl
- linux-i686-musl
- linux-armhf-gnu
- linux-arm64-gnu
- linux-arm64-musl
- linux-s390x-gnu
- linux-ppc64le-gnu
- mac-x86-64
- mac-arm64
- windows-x86-64
include:
- name: linux-amd64-gnu
os: ubuntu-latest
target: x86_64-unknown-linux-gnu
cross: false
experimental: false
- name: linux-amd64-musl
os: ubuntu-latest
target: x86_64-unknown-linux-musl
cross: true
experimental: false
- name: linux-i686-musl
os: ubuntu-latest
target: i686-unknown-linux-musl
cross: true
experimental: true
- name: linux-armhf-gnu
os: ubuntu-latest
target: armv7-unknown-linux-gnueabihf
cross: true
experimental: false
- name: linux-arm64-gnu
os: ubuntu-latest
target: aarch64-unknown-linux-gnu
cross: true
experimental: false
- name: linux-arm64-musl
os: ubuntu-latest
target: aarch64-unknown-linux-musl
cross: true
experimental: true
- name: linux-s390x-gnu
os: ubuntu-latest
target: s390x-unknown-linux-gnu
cross: true
experimental: false
- name: linux-ppc64le-gnu
os: ubuntu-latest
target: powerpc64le-unknown-linux-gnu
cross: true
experimental: false
- name: mac-x86-64
os: macos-latest
target: x86_64-apple-darwin
cross: false
experimental: false
- name: mac-arm64
os: macos-11.0
target: aarch64-apple-darwin
cross: true
experimental: true
- name: windows-x86-64
os: windows-latest
target: x86_64-pc-windows-msvc
cross: false
experimental: false
#- name: windows-arm64
# os: windows-latest
# target: aarch64-pc-windows-msvc
# cross: true
# experimental: true
name: Binaries for ${{ matrix.name }}
needs: info
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
env:
version: ${{ needs.info.outputs.cli_version }}
dst: watchexec-${{ needs.info.outputs.cli_version }}-${{ matrix.target }}
steps:
- uses: actions/checkout@v4
# https://github.com/actions/cache/issues/752
- if: ${{ runner.os == 'Windows' }}
name: Use GNU tar
shell: cmd
run: |
echo "Adding GNU tar to PATH"
echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%"
- name: Configure caching
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-${{ matrix.target }}-
${{ runner.os }}-cargo-
- run: sudo apt update
if: startsWith(matrix.os, 'ubuntu-')
- name: Add musl tools
run: sudo apt install -y musl musl-dev musl-tools
if: endsWith(matrix.target, '-musl')
- name: Add aarch-gnu tools
run: sudo apt install -y gcc-aarch64-linux-gnu
if: startsWith(matrix.target, 'aarch64-unknown-linux')
- name: Add arm7hf-gnu tools
run: sudo apt install -y gcc-arm-linux-gnueabihf
if: startsWith(matrix.target, 'armv7-unknown-linux-gnueabihf')
- name: Add s390x-gnu tools
run: sudo apt install -y gcc-s390x-linux-gnu
if: startsWith(matrix.target, 's390x-unknown-linux-gnu')
- name: Add ppc64le-gnu tools
run: sudo apt install -y gcc-powerpc64le-linux-gnu
if: startsWith(matrix.target, 'powerpc64le-unknown-linux-gnu')
- name: Install cargo-deb
if: startsWith(matrix.name, 'linux-')
uses: taiki-e/install-action@v2
with:
tool: cargo-deb
- name: Install cargo-generate-rpm
if: startsWith(matrix.name, 'linux-')
uses: taiki-e/install-action@v2
with:
tool: cargo-generate-rpm
- name: Configure toolchain
run: |
rustup toolchain install --profile minimal --no-self-update stable
rustup default stable
rustup target add ${{ matrix.target }}
- name: Install cross
if: matrix.cross
uses: taiki-e/install-action@v2
with:
tool: cross
- name: Build
shell: bash
run: |
${{ matrix.cross && 'cross' || 'cargo' }} build \
-p watchexec-cli \
--release --locked \
--target ${{ matrix.target }}
- name: Make manpage
shell: bash
run: |
cargo run -p watchexec-cli \
${{ (!matrix.cross) && '--release --target' || '' }} \
${{ (!matrix.cross) && matrix.target || '' }} \
--locked -- --manual > doc/watchexec.1
- name: Make completions
shell: bash
run: |
bin/completions \
${{ (!matrix.cross) && '--release --target' || '' }} \
${{ (!matrix.cross) && matrix.target || '' }} \
--locked
- name: Package
shell: bash
run: |
set -euxo pipefail
ext=""
[[ "${{ matrix.name }}" == windows-* ]] && ext=".exe"
bin="target/${{ matrix.target }}/release/watchexec${ext}"
objcopy --compress-debug-sections "$bin" || true
mkdir "$dst"
mkdir -p "target/release"
cp "$bin" "target/release/" # workaround for cargo-deb silliness with targets
cp "$bin" "$dst/"
cp -r crates/cli/README.md LICENSE completions doc/{logo.svg,watchexec.1{,.*}} "$dst/"
- name: Archive (tar)
if: '! startsWith(matrix.name, ''windows-'')'
run: tar cavf "$dst.tar.xz" "$dst"
- name: Archive (deb)
if: startsWith(matrix.name, 'linux-')
run: cargo deb -p watchexec-cli --no-build --no-strip --target ${{ matrix.target }} --output "$dst.deb"
- name: Archive (rpm)
if: startsWith(matrix.name, 'linux-')
shell: bash
run: |
set -euxo pipefail
shopt -s globstar
cargo generate-rpm -p crates/cli --target "${{ matrix.target }}" --target-dir "target/${{ matrix.target }}"
mv target/**/*.rpm "$dst.rpm"
- name: Archive (zip)
if: startsWith(matrix.name, 'windows-')
shell: bash
run: 7z a "$dst.zip" "$dst"
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.name }}
retention-days: 1
path: |
watchexec-*.tar.xz
watchexec-*.tar.zst
watchexec-*.deb
watchexec-*.rpm
watchexec-*.zip
upload:
needs: [build, info]
name: Checksum and publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install b3sum
uses: taiki-e/install-action@v2
with:
tool: b3sum
- uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Dist manifest
run: |
jq -ncf .github/workflows/dist-manifest.jq \
--arg version "${{ needs.info.outputs.cli_version }}" \
--arg files "$(ls watchexec-*)" \
> dist-manifest.json
- name: Bulk checksums
run: |
b3sum watchexec-* | tee B3SUMS
sha512sum watchexec-* | tee SHA512SUMS
sha256sum watchexec-* | tee SHA256SUMS
- name: File checksums
run: |
for file in watchexec-*; do
b3sum --no-names $file > "$file.b3"
sha256sum $file | cut -d ' ' -f1 > "$file.sha256"
sha512sum $file | cut -d ' ' -f1 > "$file.sha512"
done
- uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564
with:
tag_name: v${{ needs.info.outputs.cli_version }}
name: CLI v${{ needs.info.outputs.cli_version }}
append_body: true
files: |
dist-manifest.json
watchexec-*.tar.xz
watchexec-*.tar.zst
watchexec-*.deb
watchexec-*.rpm
watchexec-*.zip
*SUMS
*.b3
*.sha*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

148
.github/workflows/tests.yml vendored Normal file
View File

@ -0,0 +1,148 @@
name: Test suite
on:
workflow_dispatch:
pull_request:
types:
- opened
- reopened
- synchronize
push:
branches:
- main
tags-ignore:
- "*"
env:
CARGO_TERM_COLOR: always
CARGO_UNSTABLE_SPARSE_REGISTRY: "true"
concurrency:
group: ${{ github.workflow }}-${{ github.ref || github.run_id }}
cancel-in-progress: true
jobs:
test:
strategy:
fail-fast: false
matrix:
platform:
- macos
- ubuntu
- windows
name: Test ${{ matrix.platform }}
runs-on: "${{ matrix.platform }}-latest"
steps:
- uses: actions/checkout@v4
- name: Configure toolchain
run: |
rustup toolchain install --profile minimal --no-self-update stable
rustup default stable
# https://github.com/actions/cache/issues/752
- if: ${{ runner.os == 'Windows' }}
name: Use GNU tar
shell: cmd
run: |
echo "Adding GNU tar to PATH"
echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%"
- name: Cargo caching
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-stable-
${{ runner.os }}-cargo-
- name: Compilation caching
uses: actions/cache@v4
with:
path: target/
key: ${{ runner.os }}-target-stable-${{ hashFiles('**/Cargo.lock') }}
- name: Run test suite
run: cargo test
- name: Run watchexec-events integration tests
run: cargo test -p watchexec-events -F serde
- name: Check that CLI runs
run: cargo run -p watchexec-cli -- -1 echo
- name: Install coreutils on mac
if: ${{ matrix.platform == 'macos' }}
run: brew install coreutils
- name: Run watchexec integration tests (unix)
if: ${{ matrix.platform != 'windows' }}
run: crates/cli/run-tests.sh
shell: bash
env:
WATCHEXEC_BIN: target/debug/watchexec
- name: Run bosion integration tests
run: ./run-tests.sh
working-directory: crates/bosion
shell: bash
- name: Generate manpage
run: cargo run -p watchexec-cli -- --manual > doc/watchexec.1
- name: Check that manpage is up to date
run: git diff --exit-code -- doc/
- name: Generate completions
run: bin/completions
- name: Check that completions are up to date
run: git diff --exit-code -- completions/
cross-checks:
name: Checks only against select targets
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure toolchain
run: |
rustup toolchain install --profile minimal --no-self-update stable
rustup default stable
sudo apt-get install -y musl-tools
rustup target add x86_64-unknown-linux-musl
- name: Install cross
uses: taiki-e/install-action@v2
with:
tool: cross
- name: Cargo caching
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
key: ${{ runner.os }}-cargo-stable-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-stable-
${{ runner.os }}-cargo-
- run: cargo check --target x86_64-unknown-linux-musl
- run: cross check --target x86_64-unknown-freebsd
- run: cross check --target x86_64-unknown-netbsd
tests-pass:
if: always()
name: Tests pass
needs:
- test
- cross-checks
runs-on: ubuntu-latest
steps:
- uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
target
Cargo.lock
/watchexec-*
watchexec.*.log

1
.rustfmt.toml Normal file
View File

@ -0,0 +1 @@
hard_tabs = true

17
CITATION.cff Normal file
View File

@ -0,0 +1,17 @@
cff-version: 1.2.0
message: |
If you use this software, please cite it using these metadata.
title: "Watchexec: a tool to react to filesystem changes, and a crate ecosystem to power it"
version: "2.1.1"
date-released: 2024-04-30
repository-code: https://github.com/watchexec/watchexec
license: Apache-2.0
authors:
- family-names: Green
given-names: Matt
- family-names: Saparelli
given-names: Félix
orcid: https://orcid.org/0000-0002-2010-630X

129
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,129 @@
# Contribution guidebook
This is a fairly free-form project, with low contribution traffic.
Maintainers:
- Félix Saparelli (@passcod) (active)
- Matt Green (@mattgreen) (original author, mostly checked out)
There are a few anti goals:
- Calling watchexec is to be a **simple** exercise that remains intuitive. As a specific point, it
should not involve any piping or require xargs.
- Watchexec will not be tied to any particular ecosystem or language. Projects that themselves use
watchexec (the library) can be focused on a particular domain (for example Cargo Watch for Rust),
but watchexec itself will remain generic, usable for any purpose.
## Debugging
To enable verbose logging in tests, run with:
```console
$ env RUST_LOG=watchexec=trace,info RUST_TEST_THREADS=1 RUST_NOCAPTURE=1 cargo test --test testfile -- testname
```
To use [Tokio Console](https://github.com/tokio-rs/console):
1. Add `--cfg tokio_unstable` to your `RUSTFLAGS`.
2. Run the CLI with the `dev-console` feature.
## PR etiquette
- Maintainers are busy or may not have the bandwidth, be patient.
- Do _not_ change the version number in the PR.
- Do _not_ change Cargo.toml or other project metadata, unless specifically asked for, or if that's
the point of the PR (like adding a crates.io category).
Apart from that, welcome and thank you for your time!
## Releasing
A release goes like this:
1. A maintainer launches the ["Open a release PR" workflow](https://github.com/watchexec/watchexec/actions/workflows/release-pr.yml).
2. A PR bumping the chosen crate's version is opened. Maintainers may then add stuff to it if
needed, like changelog entries for library crates. Release notes for CLI releases go directly on
the PR.
3. When the PR is merged, the release is tagged. CLI releases also get built and distributed.
4. A maintainer then manually publishes the crate (automated publishing is blocked on crates.io
implementing [scoped tokens](https://github.com/rust-lang/crates.io/issues/5443)).
### Release order
Use this command to see the tree of workspace dependencies:
```console
$ cargo tree -p watchexec-cli | rg -F '(/' --color=never | sed 's/ v[0-9].*//'
```
## Overview
The architecture of watchexec is roughly:
- sources gather events
- events are debounced and filtered
- event(s) make it through the debounce/filters and trigger an "action"
- `on_action` handler is called, returning an `Outcome`
- outcome is processed into managing the command that watchexec is running
- outcome can also be to exit
- when a command is started, the `on_pre_spawn` and `on_post_spawn` handlers are called
- commands are also a source of events, so e.g. "command has finished" is handled by `on_action`
And this is the startup sequence:
- init config sets basic immutable facts about the runtime
- runtime starts:
- source workers start, and are passed their runtime config
- action worker starts, and is passed its runtime config
- (unless `--postpone` is given) a synthetic event is injected to kickstart things
## Guides
These are generic guides for implementing specific bits of functionality.
### Adding an event source
- add a worker for "sourcing" events. Looking at the [signal source
worker](https://github.com/watchexec/watchexec/blob/main/crates/lib/src/signal/source.rs) is
probably easiest to get started here.
- because we may not always want to enable this event source, and just to be flexible, add [runtime
config](https://github.com/watchexec/watchexec/blob/main/crates/lib/src/config.rs) for the source.
- for convenience, probably add [a method on the runtime
config](https://github.com/watchexec/watchexec/blob/main/crates/lib/src/config.rs) which
configures the most common usecase.
- because watchexec is reconfigurable, in the worker you'll need to react to config changes. Look at
how the [fs worker does it](https://github.com/watchexec/watchexec/blob/main/crates/lib/src/fs.rs)
for reference.
- you may need to [add to the event tag
enum](https://github.com/watchexec/watchexec/blob/main/crates/lib/src/event.rs).
- if you do, you should [add support to the "tagged
filterer"](https://github.com/watchexec/watchexec/blob/main/crates/filterer/tagged/src/parse.rs),
but this can be done in follow-up work.
### Process a new event in the CLI
- add an option to the
[args](https://github.com/watchexec/watchexec/blob/main/crates/cli/src/args.rs) if necessary
- add to the [runtime
config](https://github.com/watchexec/watchexec/blob/main/crates/cli/src/config/runtime.rs) when
the option is present
- process relevant events [in the action
handler](https://github.com/watchexec/watchexec/blob/main/crates/cli/src/config/runtime.rs)
---
vim: tw=100

4606
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,43 @@
[package]
name = "watchexec"
version = "0.11.0"
authors = ["Matt Green <mattgreenrocks@gmail.com>"]
[workspace]
resolver = "2"
members = [
"crates/lib",
"crates/cli",
"crates/events",
"crates/signals",
"crates/supervisor",
"crates/filterer/globset",
"crates/filterer/ignore",
"crates/bosion",
"crates/ignore-files",
"crates/project-origins",
]
[workspace.dependencies]
miette = "5.10.0"
tempfile = "3.8.0"
tracing-test = "0.2.4"
rand = "0.8"
uuid = "1.5.0"
[profile.release]
lto = true
debug = 1 # for stack traces
codegen-units = 1
strip = "symbols"
[dependencies]
glob = "0.2.11"
notify = "2.6.3"
[profile.dev.build-override]
opt-level = 0
codegen-units = 1024
debug = false
debug-assertions = false
overflow-checks = false
incremental = false
[dependencies.clap]
version = "2.14"
default-features = false
features = ["wrap_help"]
[profile.release.build-override]
opt-level = 0
codegen-units = 1024
debug = false
debug-assertions = false
overflow-checks = false
incremental = false

View File

@ -1,20 +0,0 @@
VER=$(shell grep version Cargo.toml | head -n1 | grep -Eow '".+"' | sed 's/"//g')
debug: src/* Cargo.toml
@cargo build
release: src/* Cargo.toml
@cargo build --release
clean:
@cargo clean
install: release
@cp target/release/watchexec /usr/bin
uninstall:
@rm /usr/bin/watchexec
dist-osx: release
@tar -cz -C target/release -f target/release/watchexec_osx_$(VER).tar.gz watchexec
@shasum -a 256 target/release/watchexec_osx_$(VER).tar.gz

View File

@ -1,65 +1,84 @@
#watchexec
[![CI status on main branch](https://github.com/watchexec/watchexec/actions/workflows/tests.yml/badge.svg)](https://github.com/watchexec/watchexec/actions/workflows/tests.yml)
# Watchexec
Software development often involves running the same commands over and over. Boring!
`watchexec` is a **simple**, standalone tool that watches a path and runs a command whenever it detects modifications.
`watchexec` is a simple, standalone tool that watches a path and runs a command whenever it detects modifications.
Example use cases:
* Automatically run unit tests
* Run linters/syntax checkers
* Rebuild artifacts
##Status
Beta: CLI arguments stabilizing
## Features
##Features
* Simple invocation and use
* Runs on OS X, Linux and Windows
* Monitors path specified on command line for changes
* Uses most efficient event polling mechanism for your platform (except for [BSD](https://github.com/passcod/rsnotify#todo))
* Simple invocation and use, does not require a cryptic command line involving `xargs`
* Runs on OS X, Linux, and Windows
* Monitors current directory and all subdirectories for changes
* Coalesces multiple filesystem events into one, for editors that use swap/backup files during saving
* By default, uses `.gitignore` to filter for changes
* Support for watching files with a specific extension
* Support for filtering/ignoring events based on glob patterns
* Optionally clears screen between executions
* Optionally restarts the command with every modification (good for servers)
* Does not require a language runtime
* Loads `.gitignore` and `.ignore` files
* Uses process groups to keep hold of forking programs
* Provides the paths that changed in environment variables or STDIN
* Does not require a language runtime, not tied to any particular language or ecosystem
* [And more!](./crates/cli/#features)
##Anti-Features
* Not tied to any particular language or ecosystem
* Does not require a cryptic command line involving `xargs`
## Quick start
##Usage Examples
Watch all JavaScript, CSS and HTML files in the current directory and all subdirectories for changes, running `npm run build` when a change is detected:
Watch all JavaScript, CSS and HTML files in the current directory and all subdirectories for changes, running `make` when a change is detected:
$ watchexec --exts js,css,html make
Watch all files below `src` and subdirectories for changes, running `make test` when a change is detected:
$ watchexec --watch src make test
Call `make test` when any file changes in this directory/subdirectory, except for everything below `target`:
$ watchexec -i target make
$ watchexec -e js,css,html npm run build
Call/restart `python server.py` when any Python file in the current directory (and all subdirectories) changes:
$ watchexec -e py -r python server.py
$ watchexec -r -e py -- python server.py
Run `make` when any file changes, using the `.gitignore` file in the current directory to filter:
More usage examples: [in the CLI README](./crates/cli/#usage-examples)!
$ watchexec make
## Install
##Installation
<a href="https://repology.org/project/watchexec/versions"><img align="right" src="https://repology.org/badge/vertical-allrepos/watchexec.svg" alt="Packaging status"></a>
###OS X with Homebrew
- With [your package manager](./doc/packages.md) for Arch, Debian, Homebrew, Nix, Scoop, Chocolatey…
- From binary with [Binstall](https://github.com/cargo-bins/cargo-binstall): `cargo binstall watchexec-cli`
- As [pre-built binary package from Github](https://github.com/watchexec/watchexec/releases/latest)
- From source with Cargo: `cargo install --locked watchexec-cli`
$ brew install https://raw.githubusercontent.com/mattgreen/watchexec/master/pkg/brew/watchexec.rb
All options in detail: [in the CLI README](./crates/cli/#installation),
in the online help (`watchexec -h`, `watchexec --help`, or `watchexec --manual`),
and [in the manual page](./doc/watchexec.1.md).
##Credits
* [notify](https://github.com/passcod/rsnotify) for doing most of the heavy-lifting
## Augment
Watchexec pairs well with:
- [checkexec](https://github.com/kurtbuilds/checkexec): to run only when source files are newer than a target file
- [just](https://github.com/casey/just): a modern alternative to `make`
- [systemfd](https://github.com/mitsuhiko/systemfd): socket-passing in development
## Extend
- [watchexec library](./crates/lib/): to create more specialised watchexec-powered tools.
- [watchexec-events](./crates/events/): event types for watchexec.
- [watchexec-signals](./crates/signals/): signal types for watchexec.
- [watchexec-supervisor](./crates/supervisor/): process lifecycle manager (the _exec_ part of watchexec).
- [clearscreen](https://github.com/watchexec/clearscreen): to clear the (terminal) screen on every platform.
- [command group](https://github.com/watchexec/command-group): to run commands in process groups.
- [ignore files](./crates/ignore-files/): to find, parse, and interpret ignore files.
- [project origins](./crates/project-origins/): to find the origin(s) directory of a project.
- [notify](https://github.com/notify-rs/notify): to respond to file modifications (third-party).
### Downstreams
Selected downstreams of watchexec and associated crates:
- [cargo watch](https://github.com/watchexec/cargo-watch): a specialised watcher for Rust/Cargo projects.
- [cargo lambda](https://github.com/cargo-lambda/cargo-lambda): a dev tool for Rust-powered AWS Lambda functions.
- [create-rust-app](https://create-rust-app.dev): a template for Rust+React web apps.
- [dotter](https://github.com/supercuber/dotter): a dotfile manager.
- [ghciwatch](https://github.com/mercurytechnologies/ghciwatch): a specialised watcher for Haskell projects.
- [tectonic](https://tectonic-typesetting.github.io/book/latest/): a TeX/LaTeX typesetting system.

7
bin/completions Executable file
View File

@ -0,0 +1,7 @@
#!/bin/sh
cargo run -p watchexec-cli $* -- --completions bash > completions/bash
cargo run -p watchexec-cli $* -- --completions elvish > completions/elvish
cargo run -p watchexec-cli $* -- --completions fish > completions/fish
cargo run -p watchexec-cli $* -- --completions nu > completions/nu
cargo run -p watchexec-cli $* -- --completions powershell > completions/powershell
cargo run -p watchexec-cli $* -- --completions zsh > completions/zsh

10
bin/dates.mjs Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env node
const id = Math.floor(Math.random() * 100);
let n = 0;
const m = 5;
while (n < m) {
n += 1;
console.log(`[${id} : ${n}/${m}] ${new Date}`);
await new Promise(done => setTimeout(done, 2000));
}

3
bin/manpage Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
cargo run -p watchexec-cli -- --manual > doc/watchexec.1
pandoc doc/watchexec.1 -t markdown > doc/watchexec.1.md

222
completions/bash Normal file
View File

@ -0,0 +1,222 @@
_watchexec() {
local i cur prev opts cmd
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
cmd=""
opts=""
for i in ${COMP_WORDS[@]}
do
case "${cmd},${i}" in
",$1")
cmd="watchexec"
;;
*)
;;
esac
done
case "${cmd}" in
watchexec)
opts="-w -W -c -o -r -s -d -p -n -E -1 -N -q -e -f -j -i -v -h -V --watch --watch-non-recursive --clear --on-busy-update --restart --signal --stop-signal --stop-timeout --map-signal --debounce --stdin-quit --no-vcs-ignore --no-project-ignore --no-global-ignore --no-default-ignore --no-discover-ignore --ignore-nothing --postpone --delay-run --poll --shell --no-environment --emit-events-to --only-emit-events --env --no-process-group --wrap-process --notify --color --timings --quiet --bell --project-origin --workdir --exts --filter --filter-file --filter-prog --ignore --ignore-file --fs-events --no-meta --print-events --manual --completions --verbose --log-file --help --version [COMMAND]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
--watch)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-w)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--watch-non-recursive)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-W)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--clear)
COMPREPLY=($(compgen -W "clear reset" -- "${cur}"))
return 0
;;
-c)
COMPREPLY=($(compgen -W "clear reset" -- "${cur}"))
return 0
;;
--on-busy-update)
COMPREPLY=($(compgen -W "queue do-nothing restart signal" -- "${cur}"))
return 0
;;
-o)
COMPREPLY=($(compgen -W "queue do-nothing restart signal" -- "${cur}"))
return 0
;;
--signal)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-s)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--stop-signal)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--stop-timeout)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--map-signal)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--debounce)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-d)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--delay-run)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--poll)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--shell)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--emit-events-to)
COMPREPLY=($(compgen -W "environment stdio file json-stdio json-file none" -- "${cur}"))
return 0
;;
--env)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-E)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--wrap-process)
COMPREPLY=($(compgen -W "group session none" -- "${cur}"))
return 0
;;
--color)
COMPREPLY=($(compgen -W "auto always never" -- "${cur}"))
return 0
;;
--project-origin)
COMPREPLY=()
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o plusdirs
fi
return 0
;;
--workdir)
COMPREPLY=()
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o plusdirs
fi
return 0
;;
--exts)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-e)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--filter)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-f)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--filter-file)
local oldifs
if [ -n "${IFS+x}" ]; then
oldifs="$IFS"
fi
IFS=$'\n'
COMPREPLY=($(compgen -f "${cur}"))
if [ -n "${oldifs+x}" ]; then
IFS="$oldifs"
fi
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o filenames
fi
return 0
;;
--filter-prog)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-j)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--ignore)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-i)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--ignore-file)
local oldifs
if [ -n "${IFS+x}" ]; then
oldifs="$IFS"
fi
IFS=$'\n'
COMPREPLY=($(compgen -f "${cur}"))
if [ -n "${oldifs+x}" ]; then
IFS="$oldifs"
fi
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o filenames
fi
return 0
;;
--fs-events)
COMPREPLY=($(compgen -W "access create remove rename modify metadata" -- "${cur}"))
return 0
;;
--completions)
COMPREPLY=($(compgen -W "bash elvish fish nu powershell zsh" -- "${cur}"))
return 0
;;
--log-file)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
*)
COMPREPLY=()
;;
esac
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
;;
esac
}
if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then
complete -F _watchexec -o nosort -o bashdefault -o default watchexec
else
complete -F _watchexec -o bashdefault -o default watchexec
fi

93
completions/elvish Normal file
View File

@ -0,0 +1,93 @@
use builtin;
use str;
set edit:completion:arg-completer[watchexec] = {|@words|
fn spaces {|n|
builtin:repeat $n ' ' | str:join ''
}
fn cand {|text desc|
edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc
}
var command = 'watchexec'
for word $words[1..-1] {
if (str:has-prefix $word '-') {
break
}
set command = $command';'$word
}
var completions = [
&'watchexec'= {
cand -w 'Watch a specific file or directory'
cand --watch 'Watch a specific file or directory'
cand -W 'Watch a specific directory, non-recursively'
cand --watch-non-recursive 'Watch a specific directory, non-recursively'
cand -c 'Clear screen before running command'
cand --clear 'Clear screen before running command'
cand -o 'What to do when receiving events while the command is running'
cand --on-busy-update 'What to do when receiving events while the command is running'
cand -s 'Send a signal to the process when it''s still running'
cand --signal 'Send a signal to the process when it''s still running'
cand --stop-signal 'Signal to send to stop the command'
cand --stop-timeout 'Time to wait for the command to exit gracefully'
cand --map-signal 'Translate signals from the OS to signals to send to the command'
cand -d 'Time to wait for new events before taking action'
cand --debounce 'Time to wait for new events before taking action'
cand --delay-run 'Sleep before running the command'
cand --poll 'Poll for filesystem changes'
cand --shell 'Use a different shell'
cand --emit-events-to 'Configure event emission'
cand -E 'Add env vars to the command'
cand --env 'Add env vars to the command'
cand --wrap-process 'Configure how the process is wrapped'
cand --color 'When to use terminal colours'
cand --project-origin 'Set the project origin'
cand --workdir 'Set the working directory'
cand -e 'Filename extensions to filter to'
cand --exts 'Filename extensions to filter to'
cand -f 'Filename patterns to filter to'
cand --filter 'Filename patterns to filter to'
cand --filter-file 'Files to load filters from'
cand -j '[experimental] Filter programs'
cand --filter-prog '[experimental] Filter programs'
cand -i 'Filename patterns to filter out'
cand --ignore 'Filename patterns to filter out'
cand --ignore-file 'Files to load ignores from'
cand --fs-events 'Filesystem events to filter to'
cand --completions 'Generate a shell completions script'
cand --log-file 'Write diagnostic logs to a file'
cand -r 'Restart the process if it''s still running'
cand --restart 'Restart the process if it''s still running'
cand --stdin-quit 'Exit when stdin closes'
cand --no-vcs-ignore 'Don''t load gitignores'
cand --no-project-ignore 'Don''t load project-local ignores'
cand --no-global-ignore 'Don''t load global ignores'
cand --no-default-ignore 'Don''t use internal default ignores'
cand --no-discover-ignore 'Don''t discover ignore files at all'
cand --ignore-nothing 'Don''t ignore anything at all'
cand -p 'Wait until first change before running command'
cand --postpone 'Wait until first change before running command'
cand -n 'Shorthand for ''--shell=none'''
cand --no-environment 'Deprecated shorthand for ''--emit-events=none'''
cand --only-emit-events 'Only emit events to stdout, run no commands'
cand --no-process-group 'Don''t use a process group'
cand -1 'Testing only: exit Watchexec after the first run'
cand -N 'Alert when commands start and end'
cand --notify 'Alert when commands start and end'
cand --timings 'Print how long the command took to run'
cand -q 'Don''t print starting and stopping messages'
cand --quiet 'Don''t print starting and stopping messages'
cand --bell 'Ring the terminal bell on command completion'
cand --no-meta 'Don''t emit fs events for metadata changes'
cand --print-events 'Print events that trigger actions'
cand --manual 'Show the manual page'
cand -v 'Set diagnostic log level'
cand --verbose 'Set diagnostic log level'
cand -h 'Print help (see more with ''--help'')'
cand --help 'Print help (see more with ''--help'')'
cand -V 'Print version'
cand --version 'Print version'
}
]
$completions[$command]
}

51
completions/fish Normal file
View File

@ -0,0 +1,51 @@
complete -c watchexec -s w -l watch -d 'Watch a specific file or directory' -r -F
complete -c watchexec -s W -l watch-non-recursive -d 'Watch a specific directory, non-recursively' -r -F
complete -c watchexec -s c -l clear -d 'Clear screen before running command' -r -f -a "{clear '',reset ''}"
complete -c watchexec -s o -l on-busy-update -d 'What to do when receiving events while the command is running' -r -f -a "{queue '',do-nothing '',restart '',signal ''}"
complete -c watchexec -s s -l signal -d 'Send a signal to the process when it\'s still running' -r
complete -c watchexec -l stop-signal -d 'Signal to send to stop the command' -r
complete -c watchexec -l stop-timeout -d 'Time to wait for the command to exit gracefully' -r
complete -c watchexec -l map-signal -d 'Translate signals from the OS to signals to send to the command' -r
complete -c watchexec -s d -l debounce -d 'Time to wait for new events before taking action' -r
complete -c watchexec -l delay-run -d 'Sleep before running the command' -r
complete -c watchexec -l poll -d 'Poll for filesystem changes' -r
complete -c watchexec -l shell -d 'Use a different shell' -r
complete -c watchexec -l emit-events-to -d 'Configure event emission' -r -f -a "{environment '',stdio '',file '',json-stdio '',json-file '',none ''}"
complete -c watchexec -s E -l env -d 'Add env vars to the command' -r
complete -c watchexec -l wrap-process -d 'Configure how the process is wrapped' -r -f -a "{group '',session '',none ''}"
complete -c watchexec -l color -d 'When to use terminal colours' -r -f -a "{auto '',always '',never ''}"
complete -c watchexec -l project-origin -d 'Set the project origin' -r -f -a "(__fish_complete_directories)"
complete -c watchexec -l workdir -d 'Set the working directory' -r -f -a "(__fish_complete_directories)"
complete -c watchexec -s e -l exts -d 'Filename extensions to filter to' -r
complete -c watchexec -s f -l filter -d 'Filename patterns to filter to' -r
complete -c watchexec -l filter-file -d 'Files to load filters from' -r -F
complete -c watchexec -s j -l filter-prog -d '[experimental] Filter programs' -r
complete -c watchexec -s i -l ignore -d 'Filename patterns to filter out' -r
complete -c watchexec -l ignore-file -d 'Files to load ignores from' -r -F
complete -c watchexec -l fs-events -d 'Filesystem events to filter to' -r -f -a "{access '',create '',remove '',rename '',modify '',metadata ''}"
complete -c watchexec -l completions -d 'Generate a shell completions script' -r -f -a "{bash '',elvish '',fish '',nu '',powershell '',zsh ''}"
complete -c watchexec -l log-file -d 'Write diagnostic logs to a file' -r -F
complete -c watchexec -s r -l restart -d 'Restart the process if it\'s still running'
complete -c watchexec -l stdin-quit -d 'Exit when stdin closes'
complete -c watchexec -l no-vcs-ignore -d 'Don\'t load gitignores'
complete -c watchexec -l no-project-ignore -d 'Don\'t load project-local ignores'
complete -c watchexec -l no-global-ignore -d 'Don\'t load global ignores'
complete -c watchexec -l no-default-ignore -d 'Don\'t use internal default ignores'
complete -c watchexec -l no-discover-ignore -d 'Don\'t discover ignore files at all'
complete -c watchexec -l ignore-nothing -d 'Don\'t ignore anything at all'
complete -c watchexec -s p -l postpone -d 'Wait until first change before running command'
complete -c watchexec -s n -d 'Shorthand for \'--shell=none\''
complete -c watchexec -l no-environment -d 'Deprecated shorthand for \'--emit-events=none\''
complete -c watchexec -l only-emit-events -d 'Only emit events to stdout, run no commands'
complete -c watchexec -l no-process-group -d 'Don\'t use a process group'
complete -c watchexec -s 1 -d 'Testing only: exit Watchexec after the first run'
complete -c watchexec -s N -l notify -d 'Alert when commands start and end'
complete -c watchexec -l timings -d 'Print how long the command took to run'
complete -c watchexec -s q -l quiet -d 'Don\'t print starting and stopping messages'
complete -c watchexec -l bell -d 'Ring the terminal bell on command completion'
complete -c watchexec -l no-meta -d 'Don\'t emit fs events for metadata changes'
complete -c watchexec -l print-events -d 'Print events that trigger actions'
complete -c watchexec -l manual -d 'Show the manual page'
complete -c watchexec -s v -l verbose -d 'Set diagnostic log level'
complete -c watchexec -s h -l help -d 'Print help (see more with \'--help\')'
complete -c watchexec -s V -l version -d 'Print version'

89
completions/nu Normal file
View File

@ -0,0 +1,89 @@
module completions {
def "nu-complete watchexec screen_clear" [] {
[ "clear" "reset" ]
}
def "nu-complete watchexec on_busy_update" [] {
[ "queue" "do-nothing" "restart" "signal" ]
}
def "nu-complete watchexec emit_events_to" [] {
[ "environment" "stdio" "file" "json-stdio" "json-file" "none" ]
}
def "nu-complete watchexec wrap_process" [] {
[ "group" "session" "none" ]
}
def "nu-complete watchexec color" [] {
[ "auto" "always" "never" ]
}
def "nu-complete watchexec filter_fs_events" [] {
[ "access" "create" "remove" "rename" "modify" "metadata" ]
}
def "nu-complete watchexec completions" [] {
[ "bash" "elvish" "fish" "nu" "powershell" "zsh" ]
}
# Execute commands when watched files change
export extern watchexec [
...command: string # Command to run on changes
--watch(-w): string # Watch a specific file or directory
--watch-non-recursive(-W): string # Watch a specific directory, non-recursively
--clear(-c): string@"nu-complete watchexec screen_clear" # Clear screen before running command
--on-busy-update(-o): string@"nu-complete watchexec on_busy_update" # What to do when receiving events while the command is running
--restart(-r) # Restart the process if it's still running
--signal(-s): string # Send a signal to the process when it's still running
--stop-signal: string # Signal to send to stop the command
--stop-timeout: string # Time to wait for the command to exit gracefully
--map-signal: string # Translate signals from the OS to signals to send to the command
--debounce(-d): string # Time to wait for new events before taking action
--stdin-quit # Exit when stdin closes
--no-vcs-ignore # Don't load gitignores
--no-project-ignore # Don't load project-local ignores
--no-global-ignore # Don't load global ignores
--no-default-ignore # Don't use internal default ignores
--no-discover-ignore # Don't discover ignore files at all
--ignore-nothing # Don't ignore anything at all
--postpone(-p) # Wait until first change before running command
--delay-run: string # Sleep before running the command
--poll: string # Poll for filesystem changes
--shell: string # Use a different shell
-n # Shorthand for '--shell=none'
--no-environment # Deprecated shorthand for '--emit-events=none'
--emit-events-to: string@"nu-complete watchexec emit_events_to" # Configure event emission
--only-emit-events # Only emit events to stdout, run no commands
--env(-E): string # Add env vars to the command
--no-process-group # Don't use a process group
--wrap-process: string@"nu-complete watchexec wrap_process" # Configure how the process is wrapped
-1 # Testing only: exit Watchexec after the first run
--notify(-N) # Alert when commands start and end
--color: string@"nu-complete watchexec color" # When to use terminal colours
--timings # Print how long the command took to run
--quiet(-q) # Don't print starting and stopping messages
--bell # Ring the terminal bell on command completion
--project-origin: string # Set the project origin
--workdir: string # Set the working directory
--exts(-e): string # Filename extensions to filter to
--filter(-f): string # Filename patterns to filter to
--filter-file: string # Files to load filters from
--filter-prog(-j): string # [experimental] Filter programs
--ignore(-i): string # Filename patterns to filter out
--ignore-file: string # Files to load ignores from
--fs-events: string@"nu-complete watchexec filter_fs_events" # Filesystem events to filter to
--no-meta # Don't emit fs events for metadata changes
--print-events # Print events that trigger actions
--manual # Show the manual page
--completions: string@"nu-complete watchexec completions" # Generate a shell completions script
--verbose(-v) # Set diagnostic log level
--log-file: string # Write diagnostic logs to a file
--help(-h) # Print help (see more with '--help')
--version(-V) # Print version
]
}
export use completions *

99
completions/powershell Normal file
View File

@ -0,0 +1,99 @@
using namespace System.Management.Automation
using namespace System.Management.Automation.Language
Register-ArgumentCompleter -Native -CommandName 'watchexec' -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
$commandElements = $commandAst.CommandElements
$command = @(
'watchexec'
for ($i = 1; $i -lt $commandElements.Count; $i++) {
$element = $commandElements[$i]
if ($element -isnot [StringConstantExpressionAst] -or
$element.StringConstantType -ne [StringConstantType]::BareWord -or
$element.Value.StartsWith('-') -or
$element.Value -eq $wordToComplete) {
break
}
$element.Value
}) -join ';'
$completions = @(switch ($command) {
'watchexec' {
[CompletionResult]::new('-w', 'w', [CompletionResultType]::ParameterName, 'Watch a specific file or directory')
[CompletionResult]::new('--watch', 'watch', [CompletionResultType]::ParameterName, 'Watch a specific file or directory')
[CompletionResult]::new('-W', 'W ', [CompletionResultType]::ParameterName, 'Watch a specific directory, non-recursively')
[CompletionResult]::new('--watch-non-recursive', 'watch-non-recursive', [CompletionResultType]::ParameterName, 'Watch a specific directory, non-recursively')
[CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Clear screen before running command')
[CompletionResult]::new('--clear', 'clear', [CompletionResultType]::ParameterName, 'Clear screen before running command')
[CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'What to do when receiving events while the command is running')
[CompletionResult]::new('--on-busy-update', 'on-busy-update', [CompletionResultType]::ParameterName, 'What to do when receiving events while the command is running')
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Send a signal to the process when it''s still running')
[CompletionResult]::new('--signal', 'signal', [CompletionResultType]::ParameterName, 'Send a signal to the process when it''s still running')
[CompletionResult]::new('--stop-signal', 'stop-signal', [CompletionResultType]::ParameterName, 'Signal to send to stop the command')
[CompletionResult]::new('--stop-timeout', 'stop-timeout', [CompletionResultType]::ParameterName, 'Time to wait for the command to exit gracefully')
[CompletionResult]::new('--map-signal', 'map-signal', [CompletionResultType]::ParameterName, 'Translate signals from the OS to signals to send to the command')
[CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Time to wait for new events before taking action')
[CompletionResult]::new('--debounce', 'debounce', [CompletionResultType]::ParameterName, 'Time to wait for new events before taking action')
[CompletionResult]::new('--delay-run', 'delay-run', [CompletionResultType]::ParameterName, 'Sleep before running the command')
[CompletionResult]::new('--poll', 'poll', [CompletionResultType]::ParameterName, 'Poll for filesystem changes')
[CompletionResult]::new('--shell', 'shell', [CompletionResultType]::ParameterName, 'Use a different shell')
[CompletionResult]::new('--emit-events-to', 'emit-events-to', [CompletionResultType]::ParameterName, 'Configure event emission')
[CompletionResult]::new('-E', 'E ', [CompletionResultType]::ParameterName, 'Add env vars to the command')
[CompletionResult]::new('--env', 'env', [CompletionResultType]::ParameterName, 'Add env vars to the command')
[CompletionResult]::new('--wrap-process', 'wrap-process', [CompletionResultType]::ParameterName, 'Configure how the process is wrapped')
[CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'When to use terminal colours')
[CompletionResult]::new('--project-origin', 'project-origin', [CompletionResultType]::ParameterName, 'Set the project origin')
[CompletionResult]::new('--workdir', 'workdir', [CompletionResultType]::ParameterName, 'Set the working directory')
[CompletionResult]::new('-e', 'e', [CompletionResultType]::ParameterName, 'Filename extensions to filter to')
[CompletionResult]::new('--exts', 'exts', [CompletionResultType]::ParameterName, 'Filename extensions to filter to')
[CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'Filename patterns to filter to')
[CompletionResult]::new('--filter', 'filter', [CompletionResultType]::ParameterName, 'Filename patterns to filter to')
[CompletionResult]::new('--filter-file', 'filter-file', [CompletionResultType]::ParameterName, 'Files to load filters from')
[CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, '[experimental] Filter programs')
[CompletionResult]::new('--filter-prog', 'filter-prog', [CompletionResultType]::ParameterName, '[experimental] Filter programs')
[CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'Filename patterns to filter out')
[CompletionResult]::new('--ignore', 'ignore', [CompletionResultType]::ParameterName, 'Filename patterns to filter out')
[CompletionResult]::new('--ignore-file', 'ignore-file', [CompletionResultType]::ParameterName, 'Files to load ignores from')
[CompletionResult]::new('--fs-events', 'fs-events', [CompletionResultType]::ParameterName, 'Filesystem events to filter to')
[CompletionResult]::new('--completions', 'completions', [CompletionResultType]::ParameterName, 'Generate a shell completions script')
[CompletionResult]::new('--log-file', 'log-file', [CompletionResultType]::ParameterName, 'Write diagnostic logs to a file')
[CompletionResult]::new('-r', 'r', [CompletionResultType]::ParameterName, 'Restart the process if it''s still running')
[CompletionResult]::new('--restart', 'restart', [CompletionResultType]::ParameterName, 'Restart the process if it''s still running')
[CompletionResult]::new('--stdin-quit', 'stdin-quit', [CompletionResultType]::ParameterName, 'Exit when stdin closes')
[CompletionResult]::new('--no-vcs-ignore', 'no-vcs-ignore', [CompletionResultType]::ParameterName, 'Don''t load gitignores')
[CompletionResult]::new('--no-project-ignore', 'no-project-ignore', [CompletionResultType]::ParameterName, 'Don''t load project-local ignores')
[CompletionResult]::new('--no-global-ignore', 'no-global-ignore', [CompletionResultType]::ParameterName, 'Don''t load global ignores')
[CompletionResult]::new('--no-default-ignore', 'no-default-ignore', [CompletionResultType]::ParameterName, 'Don''t use internal default ignores')
[CompletionResult]::new('--no-discover-ignore', 'no-discover-ignore', [CompletionResultType]::ParameterName, 'Don''t discover ignore files at all')
[CompletionResult]::new('--ignore-nothing', 'ignore-nothing', [CompletionResultType]::ParameterName, 'Don''t ignore anything at all')
[CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Wait until first change before running command')
[CompletionResult]::new('--postpone', 'postpone', [CompletionResultType]::ParameterName, 'Wait until first change before running command')
[CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'Shorthand for ''--shell=none''')
[CompletionResult]::new('--no-environment', 'no-environment', [CompletionResultType]::ParameterName, 'Deprecated shorthand for ''--emit-events=none''')
[CompletionResult]::new('--only-emit-events', 'only-emit-events', [CompletionResultType]::ParameterName, 'Only emit events to stdout, run no commands')
[CompletionResult]::new('--no-process-group', 'no-process-group', [CompletionResultType]::ParameterName, 'Don''t use a process group')
[CompletionResult]::new('-1', '1', [CompletionResultType]::ParameterName, 'Testing only: exit Watchexec after the first run')
[CompletionResult]::new('-N', 'N ', [CompletionResultType]::ParameterName, 'Alert when commands start and end')
[CompletionResult]::new('--notify', 'notify', [CompletionResultType]::ParameterName, 'Alert when commands start and end')
[CompletionResult]::new('--timings', 'timings', [CompletionResultType]::ParameterName, 'Print how long the command took to run')
[CompletionResult]::new('-q', 'q', [CompletionResultType]::ParameterName, 'Don''t print starting and stopping messages')
[CompletionResult]::new('--quiet', 'quiet', [CompletionResultType]::ParameterName, 'Don''t print starting and stopping messages')
[CompletionResult]::new('--bell', 'bell', [CompletionResultType]::ParameterName, 'Ring the terminal bell on command completion')
[CompletionResult]::new('--no-meta', 'no-meta', [CompletionResultType]::ParameterName, 'Don''t emit fs events for metadata changes')
[CompletionResult]::new('--print-events', 'print-events', [CompletionResultType]::ParameterName, 'Print events that trigger actions')
[CompletionResult]::new('--manual', 'manual', [CompletionResultType]::ParameterName, 'Show the manual page')
[CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'Set diagnostic log level')
[CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'Set diagnostic log level')
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
[CompletionResult]::new('-V', 'V ', [CompletionResultType]::ParameterName, 'Print version')
[CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version')
break
}
})
$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
Sort-Object -Property ListItemText
}

101
completions/zsh Normal file
View File

@ -0,0 +1,101 @@
#compdef watchexec
autoload -U is-at-least
_watchexec() {
typeset -A opt_args
typeset -a _arguments_options
local ret=1
if is-at-least 5.2; then
_arguments_options=(-s -S -C)
else
_arguments_options=(-s -C)
fi
local context curcontext="$curcontext" state line
_arguments "${_arguments_options[@]}" \
'*-w+[Watch a specific file or directory]:PATH:_files' \
'*--watch=[Watch a specific file or directory]:PATH:_files' \
'*-W+[Watch a specific directory, non-recursively]:PATH:_files' \
'*--watch-non-recursive=[Watch a specific directory, non-recursively]:PATH:_files' \
'-c+[Clear screen before running command]' \
'--clear=[Clear screen before running command]' \
'-o+[What to do when receiving events while the command is running]:MODE:(queue do-nothing restart signal)' \
'--on-busy-update=[What to do when receiving events while the command is running]:MODE:(queue do-nothing restart signal)' \
'(-r --restart)-s+[Send a signal to the process when it'\''s still running]:SIGNAL: ' \
'(-r --restart)--signal=[Send a signal to the process when it'\''s still running]:SIGNAL: ' \
'--stop-signal=[Signal to send to stop the command]:SIGNAL: ' \
'--stop-timeout=[Time to wait for the command to exit gracefully]:TIMEOUT: ' \
'*--map-signal=[Translate signals from the OS to signals to send to the command]:SIGNAL:SIGNAL: ' \
'-d+[Time to wait for new events before taking action]:TIMEOUT: ' \
'--debounce=[Time to wait for new events before taking action]:TIMEOUT: ' \
'--delay-run=[Sleep before running the command]:DURATION: ' \
'--poll=[Poll for filesystem changes]' \
'--shell=[Use a different shell]:SHELL: ' \
'--emit-events-to=[Configure event emission]:MODE:(environment stdio file json-stdio json-file none)' \
'*-E+[Add env vars to the command]:KEY=VALUE: ' \
'*--env=[Add env vars to the command]:KEY=VALUE: ' \
'--wrap-process=[Configure how the process is wrapped]:MODE:(group session none)' \
'--color=[When to use terminal colours]:MODE:(auto always never)' \
'--project-origin=[Set the project origin]:DIRECTORY:_files -/' \
'--workdir=[Set the working directory]:DIRECTORY:_files -/' \
'*-e+[Filename extensions to filter to]:EXTENSIONS: ' \
'*--exts=[Filename extensions to filter to]:EXTENSIONS: ' \
'*-f+[Filename patterns to filter to]:PATTERN: ' \
'*--filter=[Filename patterns to filter to]:PATTERN: ' \
'*--filter-file=[Files to load filters from]:PATH:_files' \
'*-j+[\[experimental\] Filter programs]:EXPRESSION: ' \
'*--filter-prog=[\[experimental\] Filter programs]:EXPRESSION: ' \
'*-i+[Filename patterns to filter out]:PATTERN: ' \
'*--ignore=[Filename patterns to filter out]:PATTERN: ' \
'*--ignore-file=[Files to load ignores from]:PATH:_files' \
'*--fs-events=[Filesystem events to filter to]:EVENTS:(access create remove rename modify metadata)' \
'(--manual)--completions=[Generate a shell completions script]:COMPLETIONS:(bash elvish fish nu powershell zsh)' \
'--log-file=[Write diagnostic logs to a file]' \
'(-o --on-busy-update)-r[Restart the process if it'\''s still running]' \
'(-o --on-busy-update)--restart[Restart the process if it'\''s still running]' \
'--stdin-quit[Exit when stdin closes]' \
'--no-vcs-ignore[Don'\''t load gitignores]' \
'--no-project-ignore[Don'\''t load project-local ignores]' \
'--no-global-ignore[Don'\''t load global ignores]' \
'--no-default-ignore[Don'\''t use internal default ignores]' \
'--no-discover-ignore[Don'\''t discover ignore files at all]' \
'--ignore-nothing[Don'\''t ignore anything at all]' \
'-p[Wait until first change before running command]' \
'--postpone[Wait until first change before running command]' \
'-n[Shorthand for '\''--shell=none'\'']' \
'--no-environment[Deprecated shorthand for '\''--emit-events=none'\'']' \
'(--completions --manual)--only-emit-events[Only emit events to stdout, run no commands]' \
'--no-process-group[Don'\''t use a process group]' \
'-1[Testing only\: exit Watchexec after the first run]' \
'-N[Alert when commands start and end]' \
'--notify[Alert when commands start and end]' \
'--timings[Print how long the command took to run]' \
'-q[Don'\''t print starting and stopping messages]' \
'--quiet[Don'\''t print starting and stopping messages]' \
'--bell[Ring the terminal bell on command completion]' \
'(--fs-events)--no-meta[Don'\''t emit fs events for metadata changes]' \
'--print-events[Print events that trigger actions]' \
'(--completions)--manual[Show the manual page]' \
'*-v[Set diagnostic log level]' \
'*--verbose[Set diagnostic log level]' \
'-h[Print help (see more with '\''--help'\'')]' \
'--help[Print help (see more with '\''--help'\'')]' \
'-V[Print version]' \
'--version[Print version]' \
'*::command -- Command to run on changes:_cmdstring' \
&& ret=0
}
(( $+functions[_watchexec_commands] )) ||
_watchexec_commands() {
local commands; commands=()
_describe -t commands 'watchexec commands' commands "$@"
}
if [ "$funcstack[1]" = "_watchexec" ]; then
_watchexec "$@"
else
compdef _watchexec watchexec
fi

View File

@ -0,0 +1,23 @@
# Changelog
## Next (YYYY-MM-DD)
## v1.1.0 (2024-05-16)
- Add `git-describe` support (#832, by @lu-zero)
## v1.0.3 (2024-04-20)
- Deps: gix 0.62
## v1.0.2 (2023-11-26)
- Deps: upgrade to gix 0.55
## v1.0.1 (2023-07-02)
- Deps: upgrade to gix 0.44
## v1.0.0 (2023-03-05)
- Initial release.

40
crates/bosion/Cargo.toml Normal file
View File

@ -0,0 +1,40 @@
[package]
name = "bosion"
version = "1.1.0"
authors = ["Félix Saparelli <felix@passcod.name>"]
license = "Apache-2.0 OR MIT"
description = "Gather build information for verbose versions flags"
keywords = ["version", "git", "verbose", "long"]
documentation = "https://docs.rs/bosion"
repository = "https://github.com/watchexec/watchexec"
readme = "README.md"
rust-version = "1.64.0"
edition = "2021"
[dependencies.time]
version = "0.3.30"
features = ["macros", "formatting"]
[dependencies.gix]
version = "0.62.0"
optional = true
default-features = false
features = ["revision"]
[features]
default = ["git", "reproducible", "std"]
### Read from git repo, provide GIT_* vars
git = ["dep:gix"]
### Read from SOURCE_DATE_EPOCH when available
reproducible = []
### Provide a long_version_with() function to add extra info
###
### Specifically this is std support for the _using_ crate, not for the bosion crate itself. It's
### assumed that the bosion crate is always std, as it runs in build.rs.
std = []

147
crates/bosion/README.md Normal file
View File

@ -0,0 +1,147 @@
# Bosion
_Gather build information for verbose versions flags._
- **[API documentation][docs]**.
- Licensed under [Apache 2.0][license] or [MIT](https://passcod.mit-license.org).
- Status: maintained.
[docs]: https://docs.rs/bosion
[license]: ../../LICENSE
## Quick start
In your `Cargo.toml`:
```toml
[build-dependencies]
bosion = "1.1.0"
```
In your `build.rs`:
```rust ,no_run
fn main() {
bosion::gather();
}
```
In your `src/main.rs`:
```rust ,ignore
include!(env!("BOSION_PATH"));
fn main() {
// default output, like rustc -Vv
println!("{}", Bosion::LONG_VERSION);
// with additional fields
println!("{}", Bosion::long_version_with(&[
("custom data", "value"),
("LLVM version", "15.0.6"),
]));
// enabled features like +feature +an-other
println!("{}", Bosion::CRATE_FEATURE_STRING);
// the raw data
println!("{}", Bosion::GIT_COMMIT_HASH);
println!("{}", Bosion::GIT_COMMIT_SHORTHASH);
println!("{}", Bosion::GIT_COMMIT_DATE);
println!("{}", Bosion::GIT_COMMIT_DATETIME);
println!("{}", Bosion::CRATE_VERSION);
println!("{:?}", Bosion::CRATE_FEATURES);
println!("{}", Bosion::BUILD_DATE);
println!("{}", Bosion::BUILD_DATETIME);
}
```
## Advanced usage
Generating a struct with public visibility:
```rust ,no_run
// build.rs
bosion::gather_pub();
```
Customising the output file and struct names:
```rust ,no_run
// build.rs
bosion::gather_to("buildinfo.rs", "Build", /* public? */ false);
```
Outputting build-time environment variables instead of source:
```rust ,ignore
// build.rs
bosion::gather_to_env();
// src/main.rs
fn main() {
println!("{}", env!("BOSION_GIT_COMMIT_HASH"));
println!("{}", env!("BOSION_GIT_COMMIT_SHORTHASH"));
println!("{}", env!("BOSION_GIT_COMMIT_DATE"));
println!("{}", env!("BOSION_GIT_COMMIT_DATETIME"));
println!("{}", env!("BOSION_BUILD_DATE"));
println!("{}", env!("BOSION_BUILD_DATETIME"));
println!("{}", env!("BOSION_CRATE_VERSION"));
println!("{}", env!("BOSION_CRATE_FEATURES")); // comma-separated
}
```
Custom env prefix:
```rust ,no_run
// build.rs
bosion::gather_to_env_with_prefix("MYAPP_");
```
## Features
- `reproducible`: reads [`SOURCE_DATE_EPOCH`](https://reproducible-builds.org/docs/source-date-epoch/) (default).
- `git`: enables gathering git information (default).
- `std`: enables the `long_version_with` method (default).
Specifically, this is about the downstream crate's std support, not Bosion's, which always requires std.
## Why not...?
- [bugreport](https://github.com/sharkdp/bugreport): runtime library, for bug information.
- [git-testament](https://github.com/kinnison/git-testament): uses the `git` CLI instead of gitoxide.
- [human-panic](https://github.com/rust-cli/human-panic): runtime library, for panics.
- [shadow-rs](https://github.com/baoyachi/shadow-rs): uses libgit2 instead of gitoxide, doesn't rebuild on git changes.
- [vergen](https://github.com/rustyhorde/vergen): uses the `git` CLI instead of gitoxide.
Bosion also requires no dependencies outside of build.rs, and was specifically made for crates
installed in a variety of ways, like with `cargo install`, from pre-built binary, from source with
git, or from source without git (like a tarball), on a variety of platforms. Its default output with
[clap](https://clap.rs) is almost exactly like `rustc -Vv`.
## Examples
The [examples](./examples) directory contains a practical and runnable [clap-based example](./examples/clap/), as well
as several other crates which are actually used for integration testing.
Here is the output for the Watchexec CLI:
```plain
watchexec 1.21.1 (5026793 2023-03-05)
commit-hash: 5026793a12ff895edf2dafb92111e7bd1767650e
commit-date: 2023-03-05
build-date: 2023-03-05
release: 1.21.1
features:
```
For comparison, here's `rustc -Vv`:
```plain
rustc 1.67.1 (d5a82bbd2 2023-02-07)
binary: rustc
commit-hash: d5a82bbd26e1ad8b7401f6a718a9c57c96905483
commit-date: 2023-02-07
host: x86_64-unknown-linux-gnu
release: 1.67.1
LLVM version: 15.0.6
```

1360
crates/bosion/examples/clap/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
[package]
name = "bosion-example-clap"
version = "0.1.0"
publish = false
edition = "2021"
[workspace]
[features]
default = ["foo"]
foo = []
[build-dependencies.bosion]
version = "*"
path = "../.."
[dependencies.clap]
version = "4.1.8"
features = ["cargo", "derive"]

View File

@ -0,0 +1,3 @@
fn main() {
bosion::gather();
}

View File

@ -0,0 +1,41 @@
use clap::Parser;
include!(env!("BOSION_PATH"));
#[derive(Parser)]
#[clap(version, long_version = Bosion::LONG_VERSION)]
struct Args {
#[clap(long)]
extras: bool,
#[clap(long)]
features: bool,
#[clap(long)]
dates: bool,
#[clap(long)]
describe: bool,
}
fn main() {
let args = Args::parse();
if args.extras {
println!(
"{}",
Bosion::long_version_with(&[("extra", "field"), ("custom", "1.2.3"),])
);
} else if args.features {
println!("Features: {}", Bosion::CRATE_FEATURE_STRING);
} else if args.dates {
println!("commit date: {}", Bosion::GIT_COMMIT_DATE);
println!("commit datetime: {}", Bosion::GIT_COMMIT_DATETIME);
println!("build date: {}", Bosion::BUILD_DATE);
println!("build datetime: {}", Bosion::BUILD_DATETIME);
} else if args.describe {
println!("commit description: {}", Bosion::GIT_COMMIT_DESCRIPTION);
} else {
println!("{}", Bosion::LONG_VERSION);
}
}

1250
crates/bosion/examples/default/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
[package]
name = "bosion-test-default"
version = "0.1.0"
publish = false
edition = "2021"
[workspace]
[features]
default = ["foo"]
foo = []
[build-dependencies.bosion]
version = "*"
path = "../.."
[dependencies]
leon = { version = "2.0.1", default-features = false }
snapbox = "0.5.9"
time = { version = "0.3.30", features = ["formatting", "macros"] }

View File

@ -0,0 +1,3 @@
fn main() {
bosion::gather();
}

View File

@ -0,0 +1,68 @@
#[cfg(test)]
pub(crate) fn git_commit_info(format: &str) -> String {
let output = std::process::Command::new("git")
.arg("show")
.arg("--no-notes")
.arg("--no-patch")
.arg(format!("--pretty=format:{format}"))
.output()
.expect("git");
String::from_utf8(output.stdout)
.expect("git")
.trim()
.to_string()
}
#[macro_export]
macro_rules! test_snapshot {
($name:ident, $actual:expr) => {
#[cfg(test)]
#[test]
fn $name() {
use std::str::FromStr;
let gittime = ::time::OffsetDateTime::from_unix_timestamp(
i64::from_str(&crate::common::git_commit_info("%ct")).expect("git i64"),
)
.expect("git time");
::snapbox::Assert::new().matches(
::leon::Template::parse(
std::fs::read_to_string(format!("../snapshots/{}.txt", stringify!($name)))
.expect("read file")
.trim(),
)
.expect("leon parse")
.render(&[
(
"today date".to_string(),
::time::OffsetDateTime::now_utc()
.format(::time::macros::format_description!("[year]-[month]-[day]"))
.unwrap(),
),
("git hash".to_string(), crate::common::git_commit_info("%H")),
(
"git shorthash".to_string(),
crate::common::git_commit_info("%h"),
),
(
"git date".to_string(),
gittime
.format(::time::macros::format_description!("[year]-[month]-[day]"))
.expect("git date format"),
),
(
"git datetime".to_string(),
gittime
.format(::time::macros::format_description!(
"[year]-[month]-[day] [hour]:[minute]:[second]"
))
.expect("git time format"),
),
])
.expect("leon render"),
$actual,
);
}
};
}

View File

@ -0,0 +1,27 @@
include!(env!("BOSION_PATH"));
mod common;
fn main() {}
test_snapshot!(crate_version, Bosion::CRATE_VERSION);
test_snapshot!(crate_features, format!("{:#?}", Bosion::CRATE_FEATURES));
test_snapshot!(build_date, Bosion::BUILD_DATE);
test_snapshot!(build_datetime, Bosion::BUILD_DATETIME);
test_snapshot!(git_commit_hash, Bosion::GIT_COMMIT_HASH);
test_snapshot!(git_commit_shorthash, Bosion::GIT_COMMIT_SHORTHASH);
test_snapshot!(git_commit_date, Bosion::GIT_COMMIT_DATE);
test_snapshot!(git_commit_datetime, Bosion::GIT_COMMIT_DATETIME);
test_snapshot!(default_long_version, Bosion::LONG_VERSION);
test_snapshot!(
default_long_version_with,
Bosion::long_version_with(&[("extra", "field"), ("custom", "1.2.3")])
);

329
crates/bosion/examples/no-git/Cargo.lock generated Normal file
View File

@ -0,0 +1,329 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
[[package]]
name = "anstyle-parse"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "bosion"
version = "1.0.2"
dependencies = [
"time",
]
[[package]]
name = "bosion-test-no-git"
version = "0.1.0"
dependencies = [
"bosion",
"leon",
"snapbox",
"time",
]
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "leon"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52df920dfe9751d43501ff2ee12dd81c457d9e810d3f64b5200ee461fe73800b"
dependencies = [
"thiserror",
]
[[package]]
name = "normalize-line-endings"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "proc-macro2"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "similar"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
[[package]]
name = "snapbox"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ac441e1ecf678f68423d47f376d53fabce1afba92c8f68e31508eb27df8562a"
dependencies = [
"anstream",
"anstyle",
"normalize-line-endings",
"similar",
"snapbox-macros",
]
[[package]]
name = "snapbox-macros"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1c4b838b05d15ab22754068cb73500b2f3b07bf09d310e15b27f88160f1de40"
dependencies = [
"anstream",
]
[[package]]
name = "syn"
version = "2.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"

View File

@ -0,0 +1,22 @@
[package]
name = "bosion-test-no-git"
version = "0.1.0"
publish = false
edition = "2021"
[workspace]
[features]
default = ["foo"]
foo = []
[build-dependencies.bosion]
version = "*"
path = "../.."
default-features = false
features = ["std"]
[dependencies]
leon = { version = "2.0.1", default-features = false }
snapbox = "0.5.9"
time = { version = "0.3.30", features = ["formatting", "macros"] }

View File

@ -0,0 +1,3 @@
fn main() {
bosion::gather();
}

View File

@ -0,0 +1,20 @@
include!(env!("BOSION_PATH"));
#[path = "../../default/src/common.rs"]
mod common;
fn main() {}
test_snapshot!(crate_version, Bosion::CRATE_VERSION);
test_snapshot!(crate_features, format!("{:#?}", Bosion::CRATE_FEATURES));
test_snapshot!(build_date, Bosion::BUILD_DATE);
test_snapshot!(build_datetime, Bosion::BUILD_DATETIME);
test_snapshot!(no_git_long_version, Bosion::LONG_VERSION);
test_snapshot!(
no_git_long_version_with,
Bosion::long_version_with(&[("extra", "field"), ("custom", "1.2.3")])
);

329
crates/bosion/examples/no-std/Cargo.lock generated Normal file
View File

@ -0,0 +1,329 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
[[package]]
name = "anstyle-parse"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "bosion"
version = "1.0.2"
dependencies = [
"time",
]
[[package]]
name = "bosion-test-no-std"
version = "0.1.0"
dependencies = [
"bosion",
"leon",
"snapbox",
"time",
]
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "leon"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52df920dfe9751d43501ff2ee12dd81c457d9e810d3f64b5200ee461fe73800b"
dependencies = [
"thiserror",
]
[[package]]
name = "normalize-line-endings"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "proc-macro2"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.198"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "similar"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
[[package]]
name = "snapbox"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ac441e1ecf678f68423d47f376d53fabce1afba92c8f68e31508eb27df8562a"
dependencies = [
"anstream",
"anstyle",
"normalize-line-endings",
"similar",
"snapbox-macros",
]
[[package]]
name = "snapbox-macros"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1c4b838b05d15ab22754068cb73500b2f3b07bf09d310e15b27f88160f1de40"
dependencies = [
"anstream",
]
[[package]]
name = "syn"
version = "2.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"

View File

@ -0,0 +1,27 @@
[package]
name = "bosion-test-no-std"
version = "0.1.0"
publish = false
edition = "2021"
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
[workspace]
[features]
default = ["foo"]
foo = []
[build-dependencies.bosion]
version = "*"
path = "../.."
default-features = false
[dependencies]
leon = { version = "2.0.1", default-features = false }
snapbox = "0.5.9"
time = { version = "0.3.30", features = ["formatting", "macros"] }

View File

@ -0,0 +1,3 @@
fn main() {
bosion::gather();
}

View File

@ -0,0 +1,32 @@
#![cfg_attr(not(test), no_main)]
#![cfg_attr(not(test), no_std)]
#[cfg(not(test))]
use core::panic::PanicInfo;
#[cfg(not(test))]
#[panic_handler]
fn panic(_panic: &PanicInfo<'_>) -> ! {
loop {}
}
include!(env!("BOSION_PATH"));
#[cfg(test)]
#[path = "../../default/src/common.rs"]
mod common;
#[cfg(test)]
mod test {
use super::*;
test_snapshot!(crate_version, Bosion::CRATE_VERSION);
test_snapshot!(crate_features, format!("{:#?}", Bosion::CRATE_FEATURES));
test_snapshot!(build_date, Bosion::BUILD_DATE);
test_snapshot!(build_datetime, Bosion::BUILD_DATETIME);
test_snapshot!(no_git_long_version, Bosion::LONG_VERSION);
}

View File

@ -0,0 +1 @@
{today date}

View File

@ -0,0 +1 @@
{today date} [..]

View File

@ -0,0 +1,4 @@
[
"default",
"foo",
]

View File

@ -0,0 +1 @@
0.1.0

View File

@ -0,0 +1,6 @@
0.1.0 ({git shorthash} {git date}) +foo
commit-hash: {git hash}
commit-date: {git date}
build-date: {today date}
release: 0.1.0
features: default,foo

View File

@ -0,0 +1,8 @@
0.1.0 ({git shorthash} {git date}) +foo
commit-hash: {git hash}
commit-date: {git date}
build-date: {today date}
release: 0.1.0
features: default,foo
extra: field
custom: 1.2.3

View File

@ -0,0 +1 @@
{git date}

View File

@ -0,0 +1 @@
{git datetime}

View File

@ -0,0 +1 @@
{git hash}

View File

@ -0,0 +1 @@
{git shorthash}

View File

@ -0,0 +1,4 @@
0.1.0 ({today date}) +foo
build-date: {today date}
release: 0.1.0
features: default,foo

View File

@ -0,0 +1,6 @@
0.1.0 ({today date}) +foo
build-date: {today date}
release: 0.1.0
features: default,foo
extra: field
custom: 1.2.3

View File

@ -0,0 +1,17 @@
pre-release-commit-message = "release: bosion v{{version}}"
tag-prefix = "bosion-"
tag-message = "bosion {{version}}"
[[pre-release-replacements]]
file = "CHANGELOG.md"
search = "^## Next.*$"
replace = "## Next (YYYY-MM-DD)\n\n## v{{version}} ({{date}})"
prerelease = true
max = 1
[[pre-release-replacements]]
file = "README.md"
search = "^bosion = \".*\"$"
replace = "bosion = \"{{version}}\""
prerelease = true
max = 1

11
crates/bosion/run-tests.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/bash
set -euo pipefail
for test in default no-git no-std; do
echo "Testing $test"
pushd examples/$test
cargo check
cargo test
popd
done

172
crates/bosion/src/info.rs Normal file
View File

@ -0,0 +1,172 @@
use std::{env::var, path::PathBuf};
use time::{format_description::FormatItem, macros::format_description, OffsetDateTime};
/// Gathered build-time information
///
/// This struct contains all the information gathered by `bosion`. It is not meant to be used
/// directly under normal circumstances, but is public for documentation purposes and if you wish
/// to build your own frontend for whatever reason. In that case, note that no effort has been made
/// to make this usable outside of the build.rs environment.
///
/// The `git` field is only available when the `git` feature is enabled, and if there is a git
/// repository to read from. The repository is discovered by walking up the directory tree until one
/// is found, which means workspaces or more complex monorepos are automatically supported. If there
/// are any errors reading the repository, the `git` field will be `None` and a rustc warning will
/// be printed.
#[derive(Debug, Clone)]
pub struct Info {
/// The crate version, as read from the `CARGO_PKG_VERSION` environment variable.
pub crate_version: String,
/// The crate features, as found by the presence of `CARGO_FEATURE_*` environment variables.
///
/// These are normalised to lowercase and have underscores replaced by hyphens.
pub crate_features: Vec<String>,
/// The build date, in the format `YYYY-MM-DD`, at UTC.
///
/// This is either current as of build time, or from the timestamp specified by the
/// `SOURCE_DATE_EPOCH` environment variable, for
/// [reproducible builds](https://reproducible-builds.org/).
pub build_date: String,
/// The build datetime, in the format `YYYY-MM-DD HH:MM:SS`, at UTC.
///
/// This is either current as of build time, or from the timestamp specified by the
/// `SOURCE_DATE_EPOCH` environment variable, for
/// [reproducible builds](https://reproducible-builds.org/).
pub build_datetime: String,
/// Git repository information, if available.
pub git: Option<GitInfo>,
}
trait ErrString<T> {
fn err_string(self) -> Result<T, String>;
}
impl<T, E> ErrString<T> for Result<T, E>
where
E: std::fmt::Display,
{
fn err_string(self) -> Result<T, String> {
self.map_err(|e| e.to_string())
}
}
const DATE_FORMAT: &[FormatItem<'static>] = format_description!("[year]-[month]-[day]");
const DATETIME_FORMAT: &[FormatItem<'static>] =
format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
impl Info {
/// Gathers build-time information
///
/// This is not meant to be used directly under normal circumstances, but is public if you wish
/// to build your own frontend for whatever reason. In that case, note that no effort has been
/// made to make this usable outside of the build.rs environment.
pub fn gather() -> Result<Self, String> {
let build_date = Self::build_date()?;
Ok(Self {
crate_version: var("CARGO_PKG_VERSION").err_string()?,
crate_features: Self::features(),
build_date: build_date.format(DATE_FORMAT).err_string()?,
build_datetime: build_date.format(DATETIME_FORMAT).err_string()?,
#[cfg(feature = "git")]
git: GitInfo::gather()
.map_err(|e| {
println!("cargo:warning=git info gathering failed: {e}");
})
.ok(),
#[cfg(not(feature = "git"))]
git: None,
})
}
fn build_date() -> Result<OffsetDateTime, String> {
if cfg!(feature = "reproducible") {
if let Ok(date) = var("SOURCE_DATE_EPOCH") {
if let Ok(date) = date.parse::<i64>() {
return OffsetDateTime::from_unix_timestamp(date).err_string();
}
}
}
Ok(OffsetDateTime::now_utc())
}
fn features() -> Vec<String> {
let mut features = Vec::new();
for (key, _) in std::env::vars() {
if let Some(stripped) = key.strip_prefix("CARGO_FEATURE_") {
features.push(stripped.replace('_', "-").to_lowercase().to_string());
}
}
features
}
pub(crate) fn set_reruns(&self) {
if cfg!(feature = "reproducible") {
println!("cargo:rerun-if-env-changed=SOURCE_DATE_EPOCH");
}
if let Some(git) = &self.git {
let git_head = git.git_root.join("HEAD");
println!("cargo:rerun-if-changed={}", git_head.display());
}
}
}
/// Git repository information
#[derive(Debug, Clone)]
pub struct GitInfo {
/// The absolute path to the git repository's data folder.
///
/// In a normal repository, this is `.git`, _not_ the index or working directory.
pub git_root: PathBuf,
/// The full hash of the current commit.
///
/// Note that this makes no effore to handle dirty working directories, so it may not be
/// representative of the current state of the code.
pub git_hash: String,
/// The short hash of the current commit.
///
/// This is read from git and not truncated manually, so it may be longer than 7 characters.
pub git_shorthash: String,
/// The date of the current commit, in the format `YYYY-MM-DD`, at UTC.
pub git_date: String,
/// The datetime of the current commit, in the format `YYYY-MM-DD HH:MM:SS`, at UTC.
pub git_datetime: String,
/// The `git describe` equivalent output
pub git_description: String,
}
#[cfg(feature = "git")]
impl GitInfo {
fn gather() -> Result<Self, String> {
use std::path::Path;
let (path, _) = gix::discover::upwards(Path::new(".")).err_string()?;
let repo = gix::discover(path).err_string()?;
let head = repo.head_commit().err_string()?;
let time = head.time().err_string()?;
let timestamp = OffsetDateTime::from_unix_timestamp(time.seconds as _).err_string()?;
Ok(Self {
git_root: repo.path().canonicalize().err_string()?,
git_hash: head.id().to_string(),
git_shorthash: head.short_id().err_string()?.to_string(),
git_date: timestamp.format(DATE_FORMAT).err_string()?,
git_datetime: timestamp.format(DATETIME_FORMAT).err_string()?,
git_description: head.describe().format().err_string()?.to_string(),
})
}
}

263
crates/bosion/src/lib.rs Normal file
View File

@ -0,0 +1,263 @@
#![doc = include_str!("../README.md")]
use std::{env::var, fs::File, io::Write, path::PathBuf};
pub use info::*;
mod info;
/// Gather build-time information for the current crate
///
/// See the crate-level documentation for a guide. This function is a convenience wrapper around
/// [`gather_to`] with the most common defaults: it writes to `bosion.rs` a pub(crate) struct named
/// `Bosion`.
pub fn gather() {
gather_to("bosion.rs", "Bosion", false);
}
/// Gather build-time information for the current crate (public visibility)
///
/// See the crate-level documentation for a guide. This function is a convenience wrapper around
/// [`gather_to`]: it writes to `bosion.rs` a pub struct named `Bosion`.
pub fn gather_pub() {
gather_to("bosion.rs", "Bosion", true);
}
/// Gather build-time information for the current crate (custom output)
///
/// Gathers a limited set of build-time information for the current crate and writes it to a file.
/// The file is always written to the `OUT_DIR` directory, as per Cargo conventions. It contains a
/// zero-size struct with a bunch of associated constants containing the gathered information, and a
/// `long_version_with` function (when the `std` feature is enabled) that takes a slice of extra
/// key-value pairs to append in the same format.
///
/// `public` controls whether the struct is `pub` (true) or `pub(crate)` (false).
///
/// The generated code is entirely documented, and will appear in your documentation (in docs.rs, it
/// only will if visibility is public).
///
/// See [`Info`] for a list of gathered data.
///
/// The constants include all the information from [`Info`], as well as the following:
///
/// - `LONG_VERSION`: A clap-ready long version string, including the crate version, features, build
/// date, and git information when available.
/// - `CRATE_FEATURE_STRING`: A string containing the crate features, in the format `+feat1 +feat2`.
///
/// We also instruct rustc to rerun the build script if the environment changes, as necessary.
pub fn gather_to(filename: &str, structname: &str, public: bool) {
let path = PathBuf::from(var("OUT_DIR").expect("bosion")).join(filename);
println!("cargo:rustc-env=BOSION_PATH={}", path.display());
let info = Info::gather().expect("bosion");
info.set_reruns();
let Info {
crate_version,
crate_features,
build_date,
build_datetime,
git,
} = info;
let crate_feature_string = crate_features
.iter()
.filter(|feat| *feat != "default")
.map(|feat| format!("+{feat}"))
.collect::<Vec<_>>()
.join(" ");
let crate_feature_list = crate_features.join(",");
let viz = if public { "pub" } else { "pub(crate)" };
let (git_render, long_version) = if let Some(GitInfo {
git_hash,
git_shorthash,
git_date,
git_datetime,
git_description,
..
}) = git
{
(format!(
"
/// The git commit hash
///
/// This is the full hash of the commit that was built. Note that if the repository was
/// dirty, this will be the hash of the last commit, not including the changes.
pub const GIT_COMMIT_HASH: &'static str = {git_hash:?};
/// The git commit hash, shortened
///
/// This is the shortened hash of the commit that was built. Same caveats as with
/// `GIT_COMMIT_HASH` apply. The length of the hash is as short as possible while still
/// being unambiguous, at build time. For large repositories, this may be longer than 7
/// characters.
pub const GIT_COMMIT_SHORTHASH: &'static str = {git_shorthash:?};
/// The git commit date
///
/// This is the date (`YYYY-MM-DD`) of the commit that was built. Same caveats as with
/// `GIT_COMMIT_HASH` apply.
pub const GIT_COMMIT_DATE: &'static str = {git_date:?};
/// The git commit date and time
///
/// This is the date and time (`YYYY-MM-DD HH:MM:SS`) of the commit that was built. Same
/// caveats as with `GIT_COMMIT_HASH` apply.
pub const GIT_COMMIT_DATETIME: &'static str = {git_datetime:?};
/// The git description
///
/// This is the string equivalent to what `git describe` would output
pub const GIT_COMMIT_DESCRIPTION: &'static str = {git_description:?};
"
), format!("{crate_version} ({git_shorthash} {git_date}) {crate_feature_string}\ncommit-hash: {git_hash}\ncommit-date: {git_date}\nbuild-date: {build_date}\nrelease: {crate_version}\nfeatures: {crate_feature_list}"))
} else {
(String::new(), format!("{crate_version} ({build_date}) {crate_feature_string}\nbuild-date: {build_date}\nrelease: {crate_version}\nfeatures: {crate_feature_list}"))
};
#[cfg(feature = "std")]
let long_version_with_fn = r#"
/// Returns the long version string with extra information tacked on
///
/// This is the same as `LONG_VERSION` but takes a slice of key-value pairs to append to the
/// end in the same format.
pub fn long_version_with(extra: &[(&str, &str)]) -> String {
let mut output = Self::LONG_VERSION.to_string();
for (k, v) in extra {
output.push_str(&format!("\n{k}: {v}"));
}
output
}
"#;
#[cfg(not(feature = "std"))]
let long_version_with_fn = "";
let bosion_version = env!("CARGO_PKG_VERSION");
let render = format!(
r#"
/// Build-time information
///
/// This struct is generated by the [bosion](https://docs.rs/bosion) crate at build time.
///
/// Bosion version: {bosion_version}
#[derive(Debug, Clone, Copy)]
{viz} struct {structname};
#[allow(dead_code)]
impl {structname} {{
/// Clap-compatible long version string
///
/// At minimum, this will be the crate version and build date.
///
/// It presents as a first "summary" line like `crate_version (build_date) features`,
/// followed by `key: value` pairs. This is the same format used by `rustc -Vv`.
///
/// If git info is available, it also includes the git hash, short hash and commit date,
/// and swaps the build date for the commit date in the summary line.
pub const LONG_VERSION: &'static str = {long_version:?};
/// The crate version, as reported by Cargo
///
/// You should probably prefer reading the `CARGO_PKG_VERSION` environment variable.
pub const CRATE_VERSION: &'static str = {crate_version:?};
/// The crate features
///
/// This is a list of the features that were enabled when this crate was built,
/// lowercased and with underscores replaced by hyphens.
pub const CRATE_FEATURES: &'static [&'static str] = &{crate_features:?};
/// The crate features, as a string
///
/// This is in format `+feature +feature2 +feature3`, lowercased with underscores
/// replaced by hyphens.
pub const CRATE_FEATURE_STRING: &'static str = {crate_feature_string:?};
/// The build date
///
/// This is the date that the crate was built, in the format `YYYY-MM-DD`. If the
/// environment variable `SOURCE_DATE_EPOCH` was set, it's used instead of the current
/// time, for [reproducible builds](https://reproducible-builds.org/).
pub const BUILD_DATE: &'static str = {build_date:?};
/// The build datetime
///
/// This is the date and time that the crate was built, in the format
/// `YYYY-MM-DD HH:MM:SS`. If the environment variable `SOURCE_DATE_EPOCH` was set, it's
/// used instead of the current time, for
/// [reproducible builds](https://reproducible-builds.org/).
pub const BUILD_DATETIME: &'static str = {build_datetime:?};
{git_render}
{long_version_with_fn}
}}
"#
);
let mut file = File::create(path).expect("bosion");
file.write_all(render.as_bytes()).expect("bosion");
}
/// Gather build-time information and write it to the environment
///
/// See the crate-level documentation for a guide. This function is a convenience wrapper around
/// [`gather_to_env_with_prefix`] with the most common default prefix of `BOSION_`.
pub fn gather_to_env() {
gather_to_env_with_prefix("BOSION_");
}
/// Gather build-time information and write it to the environment
///
/// Gathers a limited set of build-time information for the current crate and makes it available to
/// the crate as build environment variables. This is an alternative to [`include!`]ing a file which
/// is generated at build time, like for [`gather`] and variants, which doesn't create any new code
/// and doesn't include any information in the binary that you do not explicitly use.
///
/// The environment variables are prefixed with the given string, which should be generally be
/// uppercase and end with an underscore.
///
/// See [`Info`] for a list of gathered data.
///
/// Unlike [`gather`], there is no Clap-ready `LONG_VERSION` string, but you can of course generate
/// one yourself from the environment variables.
///
/// We also instruct rustc to rerun the build script if the environment changes, as necessary.
pub fn gather_to_env_with_prefix(prefix: &str) {
let info = Info::gather().expect("bosion");
info.set_reruns();
let Info {
crate_version,
crate_features,
build_date,
build_datetime,
git,
} = info;
println!("cargo:rustc-env={prefix}CRATE_VERSION={crate_version}");
println!(
"cargo:rustc-env={prefix}CRATE_FEATURES={}",
crate_features.join(",")
);
println!("cargo:rustc-env={prefix}BUILD_DATE={build_date}");
println!("cargo:rustc-env={prefix}BUILD_DATETIME={build_datetime}");
if let Some(GitInfo {
git_hash,
git_shorthash,
git_date,
git_datetime,
git_description,
..
}) = git
{
println!("cargo:rustc-env={prefix}GIT_COMMIT_HASH={git_hash}");
println!("cargo:rustc-env={prefix}GIT_COMMIT_SHORTHASH={git_shorthash}");
println!("cargo:rustc-env={prefix}GIT_COMMIT_DATE={git_date}");
println!("cargo:rustc-env={prefix}GIT_COMMIT_DATETIME={git_datetime}");
println!("cargo:rustc-env={prefix}GIT_COMMIT_DESCRIPTION={git_description}");
}
}

200
crates/cli/Cargo.toml Normal file
View File

@ -0,0 +1,200 @@
[package]
name = "watchexec-cli"
version = "2.1.1"
authors = ["Félix Saparelli <felix@passcod.name>", "Matt Green <mattgreenrocks@gmail.com>"]
license = "Apache-2.0"
description = "Executes commands in response to file modifications"
keywords = ["watcher", "filesystem", "cli", "watchexec"]
categories = ["command-line-utilities"]
documentation = "https://watchexec.github.io/docs/#watchexec"
homepage = "https://watchexec.github.io"
repository = "https://github.com/watchexec/watchexec"
readme = "README.md"
edition = "2021"
[[bin]]
name = "watchexec"
path = "src/main.rs"
[dependencies]
ahash = "0.8.6" # needs to be in sync with jaq's
argfile = "0.2.0"
chrono = "0.4.31"
clap_complete = "4.4.4"
clap_complete_nushell = "4.4.2"
clap_mangen = "0.2.15"
clearscreen = "3.0.0"
dashmap = "5.4.0"
dirs = "5.0.0"
futures = "0.3.29"
humantime = "2.1.0"
indexmap = "2.2.6" # needs to be in sync with jaq's
is-terminal = "0.4.4"
jaq-core = "1.2.1"
jaq-interpret = "1.2.1"
jaq-parse = "1.0.2"
jaq-std = "1.2.1"
jaq-syn = "1.1.0"
notify-rust = "4.9.0"
once_cell = "1.17.1"
serde_json = "1.0.107"
tempfile = "3.8.1"
termcolor = "1.4.0"
tracing = "0.1.40"
tracing-appender = "0.2.3"
which = "6.0.1"
[dependencies.blake3]
version = "1.3.3"
features = ["rayon"]
[dependencies.command-group]
version = "2.1.0"
features = ["with-tokio"]
[dependencies.clap]
version = "4.4.7"
features = ["cargo", "derive", "env", "wrap_help"]
[dependencies.console-subscriber]
version = "0.2.0"
optional = true
[dependencies.eyra]
version = "0.16.8"
features = ["log", "env_logger"]
optional = true
[dependencies.ignore-files]
version = "3.0.1"
path = "../ignore-files"
[dependencies.miette]
version = "7.2.0"
features = ["fancy"]
[dependencies.pid1]
version = "0.1.1"
optional = true
[dependencies.project-origins]
version = "1.4.0"
path = "../project-origins"
[dependencies.watchexec]
version = "4.1.0"
path = "../lib"
[dependencies.watchexec-events]
version = "3.0.0"
path = "../events"
features = ["serde"]
[dependencies.watchexec-signals]
version = "3.0.0"
path = "../signals"
[dependencies.watchexec-filterer-globset]
version = "4.0.1"
path = "../filterer/globset"
[dependencies.tokio]
version = "1.33.0"
features = [
"fs",
"io-std",
"process",
"rt",
"rt-multi-thread",
"signal",
"sync",
]
[dependencies.tracing-subscriber]
version = "0.3.6"
features = [
"env-filter",
"fmt",
"json",
"tracing-log",
"ansi",
]
[target.'cfg(target_env = "musl")'.dependencies]
mimalloc = "0.1.39"
[build-dependencies]
embed-resource = "2.4.0"
[build-dependencies.bosion]
version = "1.1.0"
path = "../bosion"
[dev-dependencies]
tracing-test = "0.2.4"
uuid = { workspace = true, features = [ "v4", "fast-rng" ] }
rand = { workspace = true }
[features]
default = ["pid1"]
## Build using Eyra's pure-Rust libc
eyra = ["dep:eyra"]
## Enables PID1 handling.
pid1 = ["dep:pid1"]
## Enables logging for PID1 handling.
pid1-withlog = ["pid1"]
## For debugging only: enables the Tokio Console.
dev-console = ["dep:console-subscriber"]
[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/v{ version }/watchexec-{ version }-{ target }.{ archive-format }"
bin-dir = "watchexec-{ version }-{ target }/{ bin }{ binary-ext }"
pkg-fmt = "txz"
[package.metadata.binstall.overrides.x86_64-pc-windows-msvc]
pkg-fmt = "zip"
[package.metadata.deb]
maintainer = "Félix Saparelli <felix@passcod.name>"
license-file = ["../../LICENSE", "0"]
section = "utility"
depends = "libc6, libgcc-s1" # not needed for musl, but see below
# conf-files = [] # look me up when config file lands
assets = [
["../../target/release/watchexec", "usr/bin/watchexec", "755"],
["README.md", "usr/share/doc/watchexec/README", "644"],
["../../doc/watchexec.1.md", "usr/share/doc/watchexec/watchexec.1.md", "644"],
["../../doc/watchexec.1", "usr/share/man/man1/watchexec.1.html", "644"],
["../../completions/bash", "usr/share/bash-completion/completions/watchexec", "644"],
["../../completions/fish", "usr/share/fish/vendor_completions.d/watchexec.fish", "644"],
["../../completions/zsh", "usr/share/zsh/site-functions/_watchexec", "644"],
["../../doc/logo.svg", "usr/share/icons/hicolor/scalable/apps/watchexec.svg", "644"],
]
[package.metadata.generate-rpm]
assets = [
{ source = "../../target/release/watchexec", dest = "/usr/bin/watchexec", mode = "755" },
{ source = "README.md", dest = "/usr/share/doc/watchexec/README", mode = "644", doc = true },
{ source = "../../doc/watchexec.1.md", dest = "/usr/share/doc/watchexec/watchexec.1.md", mode = "644", doc = true },
{ source = "../../doc/watchexec.1", dest = "/usr/share/man/man1/watchexec.1.html", mode = "644" },
{ source = "../../completions/bash", dest = "/usr/share/bash-completion/completions/watchexec", mode = "644" },
{ source = "../../completions/fish", dest = "/usr/share/fish/vendor_completions.d/watchexec.fish", mode = "644" },
{ source = "../../completions/zsh", dest = "/usr/share/zsh/site-functions/_watchexec", mode = "644" },
{ source = "../../doc/logo.svg", dest = "/usr/share/icons/hicolor/scalable/apps/watchexec.svg", mode = "644" },
# set conf = true for config file when that lands
]
auto-req = "disabled"
# technically incorrect when using musl, but these are probably
# present on every rpm-using system, so let's worry about it if
# someone asks.
[package.metadata.generate-rpm.requires]
glibc = "*"
libgcc = "*"

197
crates/cli/README.md Normal file
View File

@ -0,0 +1,197 @@
# Watchexec CLI
A simple standalone tool that watches a path and runs a command whenever it detects modifications.
Example use cases:
* Automatically run unit tests
* Run linters/syntax checkers
## Features
* Simple invocation and use
* Runs on Linux, Mac, Windows, and more
* Monitors current directory and all subdirectories for changes
* Uses efficient event polling mechanism (on Linux, Mac, Windows, BSD)
* Coalesces multiple filesystem events into one, for editors that use swap/backup files during saving
* By default, uses `.gitignore`, `.ignore`, and other such files to determine which files to ignore notifications for
* Support for watching files with a specific extension
* Support for filtering/ignoring events based on [glob patterns](https://docs.rs/globset/*/globset/#syntax)
* Launches the command in a new process group (can be disabled with `--no-process-group`)
* Optionally clears screen between executions
* Optionally restarts the command with every modification (good for servers)
* Optionally sends a desktop notification on command start and end
* Does not require a language runtime
* Sets the following environment variables in the process:
`$WATCHEXEC_COMMON_PATH` is set to the longest common path of all of the below variables, and so should be prepended to each path to obtain the full/real path.
| Variable name | Event kind |
|---|---|
| `$WATCHEXEC_CREATED_PATH` | files/folders were created |
| `$WATCHEXEC_REMOVED_PATH` | files/folders were removed |
| `$WATCHEXEC_RENAMED_PATH` | files/folders were renamed |
| `$WATCHEXEC_WRITTEN_PATH` | files/folders were modified |
| `$WATCHEXEC_META_CHANGED_PATH` | files/folders' metadata were modified |
| `$WATCHEXEC_OTHERWISE_CHANGED_PATH` | every other kind of event |
These variables may contain multiple paths: these are separated by the platform's path separator, as with the `PATH` system environment variable. On Unix that is `:`, and on Windows `;`. Within each variable, paths are deduplicated and sorted in binary order (i.e. neither Unicode nor locale aware).
This can be disabled with `--emit-events=none` or changed to JSON events on STDIN with `--emit-events=json-stdio`.
## Anti-Features
* Not tied to any particular language or ecosystem
* Not tied to Git or the presence of a repository/project
* Does not require a cryptic command line involving `xargs`
## Usage Examples
Watch all JavaScript, CSS and HTML files in the current directory and all subdirectories for changes, running `make` when a change is detected:
$ watchexec --exts js,css,html make
Call `make test` when any file changes in this directory/subdirectory, except for everything below `target`:
$ watchexec -i "target/**" make test
Call `ls -la` when any file changes in this directory/subdirectory:
$ watchexec -- ls -la
Call/restart `python server.py` when any Python file in the current directory (and all subdirectories) changes:
$ watchexec -e py -r python server.py
Call/restart `my_server` when any file in the current directory (and all subdirectories) changes, sending `SIGKILL` to stop the command:
$ watchexec -r --stop-signal SIGKILL my_server
Send a SIGHUP to the command upon changes (Note: using `-n` here we're executing `my_server` directly, instead of wrapping it in a shell:
$ watchexec -n --signal SIGHUP my_server
Run `make` when any file changes, using the `.gitignore` file in the current directory to filter:
$ watchexec make
Run `make` when any file in `lib` or `src` changes:
$ watchexec -w lib -w src make
Run `bundle install` when the `Gemfile` changes:
$ watchexec -w Gemfile bundle install
Run two commands:
$ watchexec 'date; make'
Get desktop ("toast") notifications when the command starts and finishes:
$ watchexec -N go build
Only run when files are created:
$ watchexec --fs-events create -- s3 sync . s3://my-bucket
If you come from `entr`, note that the watchexec command is run in a shell by default. You can use `-n` or `--shell=none` to not do that:
$ watchexec -n -- echo ';' lorem ipsum
On Windows, you may prefer to use Powershell:
$ watchexec --shell=pwsh -- Test-Connection example.com
You can eschew running commands entirely and get a stream of events to process on your own:
```console
$ watchexec --emit-events-to=json-stdio --only-emit-events
{"tags":[{"kind":"source","source":"filesystem"},{"kind":"fs","simple":"modify","full":"Modify(Data(Any))"},{"kind":"path","absolute":"/home/code/rust/watchexec/crates/cli/README.md","filetype":"file"}]}
{"tags":[{"kind":"source","source":"filesystem"},{"kind":"fs","simple":"modify","full":"Modify(Data(Any))"},{"kind":"path","absolute":"/home/code/rust/watchexec/crates/lib/Cargo.toml","filetype":"file"}]}
{"tags":[{"kind":"source","source":"filesystem"},{"kind":"fs","simple":"modify","full":"Modify(Data(Any))"},{"kind":"path","absolute":"/home/code/rust/watchexec/crates/cli/src/args.rs","filetype":"file"}]}
```
Print the time commands take to run:
```console
$ watchexec --timings -- make
[Running: make]
...
[Command was successful, lasted 52.748081074s]
```
## Installation
### Package manager
Watchexec is in many package managers. A full list of [known packages](../../doc/packages.md) is available,
and there may be more out there! Please contribute any you find to the list :)
Common package managers:
- Alpine: `$ apk add watchexec`
- ArchLinux: `$ pacman -S watchexec`
- Nix: `$ nix-shell -p watchexec`
- Debian/Ubuntu via [apt.cli.rs](https://apt.cli.rs): `$ apt install watchexec`
- Homebrew on Mac: `$ brew install watchexec`
- Chocolatey on Windows: `#> choco install watchexec`
### [Binstall](https://github.com/cargo-bins/cargo-binstall)
$ cargo binstall watchexec-cli
### Pre-built binaries
Use the download section on [Github](https://github.com/watchexec/watchexec/releases/latest)
or [the website](https://watchexec.github.io/downloads/) to obtain the package appropriate for your
platform and architecture, extract it, and place it in your `PATH`.
There are also Debian/Ubuntu (DEB) and Fedora/RedHat (RPM) packages.
Checksums and signatures are available.
### Cargo (from source)
Only the latest Rust stable is supported, but older versions may work.
$ cargo install watchexec-cli
## Shell completions
Currently available shell completions:
- bash: `completions/bash` should be installed to `/usr/share/bash-completion/completions/watchexec`
- elvish: `completions/elvish` should be installed to `$XDG_CONFIG_HOME/elvish/completions/`
- fish: `completions/fish` should be installed to `/usr/share/fish/vendor_completions.d/watchexec.fish`
- nu: `completions/nu` should be installed to `$XDG_CONFIG_HOME/nu/completions/`
- powershell: `completions/powershell` should be installed to `$PROFILE/`
- zsh: `completions/zsh` should be installed to `/usr/share/zsh/site-functions/_watchexec`
If not bundled, you can generate completions for your shell with `watchexec --completions <shell>`.
## Manual
There's a manual page at `doc/watchexec.1`. Install it to `/usr/share/man/man1/`.
If not bundled, you can generate a manual page with `watchexec --manual > /path/to/watchexec.1`, or view it inline with `watchexec --manual` (requires `man`).
You can also [read a text version](../../doc/watchexec.1.md).
Note that it is automatically generated from the help text, so it is not as pretty as a carefully hand-written one.
## Advanced builds
These are additional options available with custom builds by setting features:
### PID1
If you're using Watchexec as PID1 (most frequently in containers or namespaces), and it's not doing what you expect, you can create a build with PID1 early logging: `--features pid1-withlog`.
If you don't need PID1 support, or if you're doing something that conflicts with this program's PID1 support, you can disable it with `--no-default-features`.
### Eyra
[Eyra](https://github.com/sunfishcode/eyra) is a system to build Linux programs with no dependency on C code (in the libc path). To build Watchexec like this, use `--features eyra` and a Nightly compiler.
This feature also lets you get early logging into program startup, with `RUST_LOG=trace`.

8
crates/cli/build.rs Normal file
View File

@ -0,0 +1,8 @@
fn main() {
embed_resource::compile("watchexec-manifest.rc", embed_resource::NONE);
bosion::gather();
if std::env::var("CARGO_FEATURE_EYRA").is_ok() {
println!("cargo:rustc-link-arg=-nostartfiles");
}
}

7
crates/cli/integration/env.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
set -euxo pipefail
watchexec=${WATCHEXEC_BIN:-watchexec}
$watchexec -1 --env FOO=BAR echo '$FOO' | grep BAR

View File

@ -0,0 +1,7 @@
#!/bin/bash
set -euxo pipefail
watchexec=${WATCHEXEC_BIN:-watchexec}
$watchexec -1 -n echo 'foo bar' | grep 'foo bar'

View File

@ -0,0 +1,7 @@
#!/bin/bash
set -euxo pipefail
watchexec=${WATCHEXEC_BIN:-watchexec}
timeout -s9 30s sh -c "sleep 10 | $watchexec --stdin-quit echo"

View File

@ -0,0 +1,7 @@
#!/bin/bash
set -euxo pipefail
watchexec=${WATCHEXEC_BIN:-watchexec}
$watchexec -1 -- echo @trailingargfile

26
crates/cli/release.toml Normal file
View File

@ -0,0 +1,26 @@
pre-release-commit-message = "release: cli v{{version}}"
tag-prefix = ""
tag-message = "watchexec {{version}}"
pre-release-hook = ["sh", "-c", "cd ../.. && bin/completions && bin/manpage"]
[[pre-release-replacements]]
file = "watchexec.exe.manifest"
search = "^ version=\"[\\d.]+[.]0\""
replace = " version=\"{{version}}.0\""
prerelease = false
max = 1
[[pre-release-replacements]]
file = "../../CITATION.cff"
search = "^version: \"?[\\d.]+(-.+)?\"?"
replace = "version: \"{{version}}\""
prerelease = true
max = 1
[[pre-release-replacements]]
file = "../../CITATION.cff"
search = "^date-released: .+"
replace = "date-released: {{date}}"
prerelease = true
max = 1

13
crates/cli/run-tests.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
set -euo pipefail
export WATCHEXEC_BIN=$(realpath ${WATCHEXEC_BIN:-$(which watchexec)})
cd "$(dirname "${BASH_SOURCE[0]}")/integration"
for test in *.sh; do
echo
echo
echo "======= Testing $test ======="
./$test
done

1298
crates/cli/src/args.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
use std::{env::var, io::stderr, path::PathBuf};
use clap::{ArgAction, Parser, ValueHint};
use miette::{bail, Result};
use tokio::fs::metadata;
use tracing::{info, warn};
use tracing_appender::{non_blocking, non_blocking::WorkerGuard, rolling};
#[derive(Debug, Clone, Parser)]
pub struct LoggingArgs {
/// Set diagnostic log level
///
/// This enables diagnostic logging, which is useful for investigating bugs or gaining more
/// insight into faulty filters or "missing" events. Use multiple times to increase verbosity.
///
/// Goes up to '-vvvv'. When submitting bug reports, default to a '-vvv' log level.
///
/// You may want to use with '--log-file' to avoid polluting your terminal.
///
/// Setting $RUST_LOG also works, and takes precedence, but is not recommended. However, using
/// $RUST_LOG is the only way to get logs from before these options are parsed.
#[arg(
long,
short,
help_heading = super::OPTSET_DEBUGGING,
action = ArgAction::Count,
default_value = "0",
num_args = 0,
)]
pub verbose: u8,
/// Write diagnostic logs to a file
///
/// This writes diagnostic logs to a file, instead of the terminal, in JSON format. If a log
/// level was not already specified, this will set it to '-vvv'.
///
/// If a path is not provided, the default is the working directory. Note that with
/// '--ignore-nothing', the write events to the log will likely get picked up by Watchexec,
/// causing a loop; prefer setting a path outside of the watched directory.
///
/// If the path provided is a directory, a file will be created in that directory. The file name
/// will be the current date and time, in the format 'watchexec.YYYY-MM-DDTHH-MM-SSZ.log'.
#[arg(
long,
help_heading = super::OPTSET_DEBUGGING,
num_args = 0..=1,
default_missing_value = ".",
value_hint = ValueHint::AnyPath,
value_name = "PATH",
)]
pub log_file: Option<PathBuf>,
}
pub fn preargs() -> bool {
let mut log_on = false;
#[cfg(feature = "dev-console")]
match console_subscriber::try_init() {
Ok(_) => {
warn!("dev-console enabled");
log_on = true;
}
Err(e) => {
eprintln!("Failed to initialise tokio console, falling back to normal logging\n{e}")
}
}
if !log_on && var("RUST_LOG").is_ok() {
match tracing_subscriber::fmt::try_init() {
Ok(()) => {
warn!(RUST_LOG=%var("RUST_LOG").unwrap(), "logging configured from RUST_LOG");
log_on = true;
}
Err(e) => eprintln!("Failed to initialise logging with RUST_LOG, falling back\n{e}"),
}
}
log_on
}
pub async fn postargs(args: &LoggingArgs) -> Result<Option<WorkerGuard>> {
if args.verbose == 0 {
return Ok(None);
}
let (log_writer, guard) = if let Some(file) = &args.log_file {
let is_dir = metadata(&file).await.map_or(false, |info| info.is_dir());
let (dir, filename) = if is_dir {
(
file.to_owned(),
PathBuf::from(format!(
"watchexec.{}.log",
chrono::Utc::now().format("%Y-%m-%dT%H-%M-%SZ")
)),
)
} else if let (Some(parent), Some(file_name)) = (file.parent(), file.file_name()) {
(parent.into(), PathBuf::from(file_name))
} else {
bail!("Failed to determine log file name");
};
non_blocking(rolling::never(dir, filename))
} else {
non_blocking(stderr())
};
let mut builder = tracing_subscriber::fmt().with_env_filter(match args.verbose {
0 => unreachable!("checked by if earlier"),
1 => "warn",
2 => "info",
3 => "debug",
_ => "trace",
});
if args.verbose > 2 {
use tracing_subscriber::fmt::format::FmtSpan;
builder = builder.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE);
}
match if args.log_file.is_some() {
builder.json().with_writer(log_writer).try_init()
} else if args.verbose > 3 {
builder.pretty().with_writer(log_writer).try_init()
} else {
builder.with_writer(log_writer).try_init()
} {
Ok(()) => info!("logging initialised"),
Err(e) => eprintln!("Failed to initialise logging, continuing with none\n{e}"),
}
Ok(Some(guard))
}

708
crates/cli/src/config.rs Normal file
View File

@ -0,0 +1,708 @@
use std::{
borrow::Cow,
collections::HashMap,
env::var,
ffi::{OsStr, OsString},
fs::File,
io::{IsTerminal, Write},
process::Stdio,
sync::{
atomic::{AtomicBool, AtomicU8, Ordering},
Arc,
},
time::Duration,
};
use clearscreen::ClearScreen;
use miette::{miette, IntoDiagnostic, Report, Result};
use notify_rust::Notification;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
use tokio::{process::Command as TokioCommand, time::sleep};
use tracing::{debug, debug_span, error, instrument, trace, trace_span, Instrument};
use watchexec::{
action::ActionHandler,
command::{Command, Program, Shell, SpawnOptions},
error::RuntimeError,
job::{CommandState, Job},
sources::fs::Watcher,
Config, ErrorHook, Id,
};
use watchexec_events::{Event, Keyboard, ProcessEnd, Tag};
use watchexec_signals::Signal;
use crate::{
args::{Args, ClearMode, ColourMode, EmitEvents, OnBusyUpdate, SignalMapping, WrapMode},
state::RotatingTempFile,
};
use crate::{emits::events_to_simple_format, state::State};
#[derive(Clone, Copy, Debug)]
struct OutputFlags {
quiet: bool,
colour: ColorChoice,
timings: bool,
bell: bool,
toast: bool,
}
pub fn make_config(args: &Args, state: &State) -> Result<Config> {
let _span = debug_span!("args-runtime").entered();
let config = Config::default();
config.on_error(|err: ErrorHook| {
if let RuntimeError::IoError {
about: "waiting on process group",
..
} = err.error
{
// "No child processes" and such
// these are often spurious, so condemn them to -v only
error!("{}", err.error);
return;
}
if cfg!(debug_assertions) {
eprintln!("[[{:?}]]", err.error);
}
eprintln!("[[Error (not fatal)]]\n{}", Report::new(err.error));
});
config.pathset(args.paths.clone());
config.throttle(args.debounce.0);
config.keyboard_events(args.stdin_quit);
if let Some(interval) = args.poll {
config.file_watcher(Watcher::Poll(interval.0));
}
let once = args.once;
let clear = args.screen_clear;
let emit_events_to = args.emit_events_to;
let emit_file = state.emit_file.clone();
if args.only_emit_events {
config.on_action(move |mut action| {
// if we got a terminate or interrupt signal, quit
if action
.signals()
.any(|sig| sig == Signal::Terminate || sig == Signal::Interrupt)
{
// no need to be graceful as there's no commands
action.quit();
return action;
}
// clear the screen before printing events
if let Some(mode) = clear {
match mode {
ClearMode::Clear => {
clearscreen::clear().ok();
}
ClearMode::Reset => {
reset_screen();
}
}
}
match emit_events_to {
EmitEvents::Stdio => {
println!(
"{}",
events_to_simple_format(action.events.as_ref()).unwrap_or_default()
);
}
EmitEvents::JsonStdio => {
for event in action.events.iter().filter(|e| !e.is_empty()) {
println!("{}", serde_json::to_string(event).unwrap_or_default());
}
}
other => unreachable!(
"emit_events_to should have been validated earlier: {:?}",
other
),
}
action
});
return Ok(config);
}
let delay_run = args.delay_run.map(|ts| ts.0);
let on_busy = args.on_busy_update;
let stdin_quit = args.stdin_quit;
let signal = args.signal;
let stop_signal = args.stop_signal;
let stop_timeout = args.stop_timeout.0;
let print_events = args.print_events;
let outflags = OutputFlags {
quiet: args.quiet,
colour: match args.color {
ColourMode::Auto if !std::io::stdin().is_terminal() => ColorChoice::Never,
ColourMode::Auto => ColorChoice::Auto,
ColourMode::Always => ColorChoice::Always,
ColourMode::Never => ColorChoice::Never,
},
timings: args.timings,
bell: args.bell,
toast: args.notify,
};
let workdir = Arc::new(args.workdir.clone());
let mut add_envs = HashMap::new();
for pair in &args.env {
if let Some((k, v)) = pair.split_once('=') {
add_envs.insert(k.to_owned(), OsString::from(v));
} else {
return Err(miette!("{pair} is not in key=value format"));
}
}
debug!(
?add_envs,
"additional environment variables to add to command"
);
let id = Id::default();
let command = interpret_command_args(args)?;
let signal_map: Arc<HashMap<Signal, Option<Signal>>> = Arc::new(
args.signal_map
.iter()
.copied()
.map(|SignalMapping { from, to }| (from, to))
.collect(),
);
let queued = Arc::new(AtomicBool::new(false));
let quit_again = Arc::new(AtomicU8::new(0));
config.on_action_async(move |mut action| {
let add_envs = add_envs.clone();
let command = command.clone();
let emit_file = emit_file.clone();
let queued = queued.clone();
let quit_again = quit_again.clone();
let signal_map = signal_map.clone();
let workdir = workdir.clone();
Box::new(
async move {
trace!(events=?action.events, "handling action");
let add_envs = add_envs.clone();
let command = command.clone();
let emit_file = emit_file.clone();
let queued = queued.clone();
let quit_again = quit_again.clone();
let signal_map = signal_map.clone();
let workdir = workdir.clone();
trace!("set spawn hook for workdir and environment variables");
let job = action.get_or_create_job(id, move || command.clone());
let events = action.events.clone();
job.set_spawn_hook(move |command, _| {
let add_envs = add_envs.clone();
let emit_file = emit_file.clone();
let events = events.clone();
if let Some(ref workdir) = workdir.as_ref() {
debug!(?workdir, "set command workdir");
command.command_mut().current_dir(workdir);
}
emit_events_to_command(
command.command_mut(),
events,
emit_file,
emit_events_to,
add_envs,
);
});
let show_events = {
let events = action.events.clone();
move || {
if print_events {
trace!("print events to stderr");
for (n, event) in events.iter().enumerate() {
eprintln!("[EVENT {n}] {event}");
}
}
}
};
let clear_screen = {
let events = action.events.clone();
move || {
if let Some(mode) = clear {
match mode {
ClearMode::Clear => {
clearscreen::clear().ok();
debug!("cleared screen");
}
ClearMode::Reset => {
reset_screen();
debug!("hard-reset screen");
}
}
}
// re-show events after clearing
if print_events {
trace!("print events to stderr");
for (n, event) in events.iter().enumerate() {
eprintln!("[EVENT {n}] {event}");
}
}
}
};
let quit = |mut action: ActionHandler| {
match quit_again.fetch_add(1, Ordering::Relaxed) {
0 => {
eprintln!("[Waiting {stop_timeout:?} for processes to exit before stopping...]");
// eprintln!("[Waiting {stop_timeout:?} for processes to exit before stopping... Ctrl-C again to exit faster]");
// see TODO in action/worker.rs
action.quit_gracefully(
stop_signal.unwrap_or(Signal::Terminate),
stop_timeout,
);
}
1 => {
action.quit_gracefully(Signal::ForceStop, Duration::ZERO);
}
_ => {
action.quit();
}
}
action
};
if once {
debug!("debug mode: run once and quit");
show_events();
if let Some(delay) = delay_run {
job.run_async(move |_| {
Box::new(async move {
sleep(delay).await;
})
});
}
// this blocks the event loop, but also this is a debug feature so i don't care
job.start().await;
job.to_wait().await;
return quit(action);
}
let is_keyboard_eof = action
.events
.iter()
.any(|e| e.tags.contains(&Tag::Keyboard(Keyboard::Eof)));
if stdin_quit && is_keyboard_eof {
debug!("keyboard EOF, quit");
show_events();
return quit(action);
}
let signals: Vec<Signal> = action.signals().collect();
trace!(?signals, "received some signals");
// if we got a terminate or interrupt signal and they're not mapped, quit
if (signals.contains(&Signal::Terminate)
&& !signal_map.contains_key(&Signal::Terminate))
|| (signals.contains(&Signal::Interrupt)
&& !signal_map.contains_key(&Signal::Interrupt))
{
debug!("unmapped terminate or interrupt signal, quit");
show_events();
return quit(action);
}
// pass all other signals on
for signal in signals {
match signal_map.get(&signal) {
Some(Some(mapped)) => {
debug!(?signal, ?mapped, "passing mapped signal");
job.signal(*mapped);
}
Some(None) => {
debug!(?signal, "discarding signal");
}
None => {
debug!(?signal, "passing signal on");
job.signal(signal);
}
}
}
// only filesystem events below here (or empty synthetic events)
if action.paths().next().is_none() && !action.events.iter().any(|e| e.is_empty()) {
debug!("no filesystem or synthetic events, skip without doing more");
show_events();
return action;
}
show_events();
if let Some(delay) = delay_run {
trace!("delaying run by sleeping inside the job");
job.run_async(move |_| {
Box::new(async move {
sleep(delay).await;
})
});
}
trace!("querying job state via run_async");
job.run_async({
let job = job.clone();
move |context| {
let job = job.clone();
let is_running = matches!(context.current, CommandState::Running { .. });
Box::new(async move {
let innerjob = job.clone();
if is_running {
trace!(?on_busy, "job is running, decide what to do");
match on_busy {
OnBusyUpdate::DoNothing => {}
OnBusyUpdate::Signal => {
job.signal(if cfg!(windows) {
Signal::ForceStop
} else {
stop_signal.or(signal).unwrap_or(Signal::Terminate)
});
}
OnBusyUpdate::Restart if cfg!(windows) => {
job.restart();
job.run(move |context| {
clear_screen();
setup_process(
innerjob.clone(),
context.command.clone(),
outflags,
)
});
}
OnBusyUpdate::Restart => {
job.restart_with_signal(
stop_signal.unwrap_or(Signal::Terminate),
stop_timeout,
);
job.run(move |context| {
clear_screen();
setup_process(
innerjob.clone(),
context.command.clone(),
outflags,
)
});
}
OnBusyUpdate::Queue => {
let job = job.clone();
let already_queued =
queued.fetch_or(true, Ordering::SeqCst);
if already_queued {
debug!("next start is already queued, do nothing");
} else {
debug!("queueing next start of job");
tokio::spawn({
let queued = queued.clone();
async move {
trace!("waiting for job to finish");
job.to_wait().await;
trace!("job finished, starting queued");
job.start();
job.run(move |context| {
clear_screen();
setup_process(
innerjob.clone(),
context.command.clone(),
outflags,
)
})
.await;
trace!("resetting queued state");
queued.store(false, Ordering::SeqCst);
}
});
}
}
}
} else {
trace!("job is not running, start it");
job.start();
job.run(move |context| {
clear_screen();
setup_process(
innerjob.clone(),
context.command.clone(),
outflags,
)
});
}
})
}
});
action
}
.instrument(trace_span!("action handler")),
)
});
Ok(config)
}
#[instrument(level = "debug")]
fn interpret_command_args(args: &Args) -> Result<Arc<Command>> {
let mut cmd = args.command.clone();
if cmd.is_empty() {
panic!("(clap) Bug: command is not present");
}
let shell = if args.no_shell {
None
} else {
let shell = args.shell.clone().or_else(|| var("SHELL").ok());
match shell
.as_deref()
.or_else(|| {
if cfg!(not(windows)) {
Some("sh")
} else if var("POWERSHELL_DISTRIBUTION_CHANNEL").is_ok()
&& (which::which("pwsh").is_ok() || which::which("pwsh.exe").is_ok())
{
trace!("detected pwsh");
Some("pwsh")
} else if var("PSModulePath").is_ok()
&& (which::which("powershell").is_ok()
|| which::which("powershell.exe").is_ok())
{
trace!("detected powershell");
Some("powershell")
} else {
Some("cmd")
}
})
.or(Some("default"))
{
Some("") => return Err(RuntimeError::CommandShellEmptyShell).into_diagnostic(),
Some("none") | None => None,
#[cfg(windows)]
Some("cmd") | Some("cmd.exe") | Some("CMD") | Some("CMD.EXE") => Some(Shell::cmd()),
Some(other) => {
let sh = other.split_ascii_whitespace().collect::<Vec<_>>();
// UNWRAP: checked by Some("")
#[allow(clippy::unwrap_used)]
let (shprog, shopts) = sh.split_first().unwrap();
Some(Shell {
prog: shprog.into(),
options: shopts.iter().map(|s| (*s).to_string()).collect(),
program_option: Some(Cow::Borrowed(OsStr::new("-c"))),
})
}
}
};
let program = if let Some(shell) = shell {
Program::Shell {
shell,
command: cmd.join(" "),
args: Vec::new(),
}
} else {
Program::Exec {
prog: cmd.remove(0).into(),
args: cmd,
}
};
Ok(Arc::new(Command {
program,
options: SpawnOptions {
grouped: matches!(args.wrap_process, WrapMode::Group),
session: matches!(args.wrap_process, WrapMode::Session),
..Default::default()
},
}))
}
#[instrument(level = "trace")]
fn setup_process(job: Job, command: Arc<Command>, outflags: OutputFlags) {
if outflags.toast {
Notification::new()
.summary("Watchexec: change detected")
.body(&format!("Running {command}"))
.show()
.map_or_else(
|err| {
eprintln!("[[Failed to send desktop notification: {err}]]");
},
drop,
);
}
if !outflags.quiet {
let mut stderr = StandardStream::stderr(outflags.colour);
stderr.reset().ok();
stderr
.set_color(ColorSpec::new().set_fg(Some(Color::Green)))
.ok();
writeln!(&mut stderr, "[Running: {command}]").ok();
stderr.reset().ok();
}
tokio::spawn(async move {
job.to_wait().await;
job.run(move |context| end_of_process(context.current, outflags));
});
}
#[instrument(level = "trace")]
fn end_of_process(state: &CommandState, outflags: OutputFlags) {
let CommandState::Finished {
status,
started,
finished,
} = state
else {
return;
};
let duration = *finished - *started;
let timing = if outflags.timings {
format!(", lasted {duration:?}")
} else {
String::new()
};
let (msg, fg) = match status {
ProcessEnd::ExitError(code) => (format!("Command exited with {code}{timing}"), Color::Red),
ProcessEnd::ExitSignal(sig) => {
(format!("Command killed by {sig:?}{timing}"), Color::Magenta)
}
ProcessEnd::ExitStop(sig) => (format!("Command stopped by {sig:?}{timing}"), Color::Blue),
ProcessEnd::Continued => (format!("Command continued{timing}"), Color::Cyan),
ProcessEnd::Exception(ex) => (
format!("Command ended by exception {ex:#x}{timing}"),
Color::Yellow,
),
ProcessEnd::Success => (format!("Command was successful{timing}"), Color::Green),
};
if outflags.toast {
Notification::new()
.summary("Watchexec: command ended")
.body(&msg)
.show()
.map_or_else(
|err| {
eprintln!("[[Failed to send desktop notification: {err}]]");
},
drop,
);
}
if !outflags.quiet {
let mut stderr = StandardStream::stderr(outflags.colour);
stderr.reset().ok();
stderr.set_color(ColorSpec::new().set_fg(Some(fg))).ok();
writeln!(&mut stderr, "[{msg}]").ok();
stderr.reset().ok();
}
if outflags.bell {
let mut stdout = std::io::stdout();
stdout.write_all(b"\x07").ok();
stdout.flush().ok();
}
}
#[instrument(level = "trace")]
fn emit_events_to_command(
command: &mut TokioCommand,
events: Arc<[Event]>,
emit_file: RotatingTempFile,
emit_events_to: EmitEvents,
mut add_envs: HashMap<String, OsString>,
) {
use crate::emits::*;
let mut stdin = None;
match emit_events_to {
EmitEvents::Environment => {
add_envs.extend(emits_to_environment(&events));
}
EmitEvents::Stdio => match emits_to_file(&emit_file, &events)
.and_then(|path| File::open(path).into_diagnostic())
{
Ok(file) => {
stdin.replace(Stdio::from(file));
}
Err(err) => {
error!("Failed to write events to stdin, continuing without it: {err}");
}
},
EmitEvents::File => match emits_to_file(&emit_file, &events) {
Ok(path) => {
add_envs.insert("WATCHEXEC_EVENTS_FILE".into(), path.into());
}
Err(err) => {
error!("Failed to write WATCHEXEC_EVENTS_FILE, continuing without it: {err}");
}
},
EmitEvents::JsonStdio => match emits_to_json_file(&emit_file, &events)
.and_then(|path| File::open(path).into_diagnostic())
{
Ok(file) => {
stdin.replace(Stdio::from(file));
}
Err(err) => {
error!("Failed to write events to stdin, continuing without it: {err}");
}
},
EmitEvents::JsonFile => match emits_to_json_file(&emit_file, &events) {
Ok(path) => {
add_envs.insert("WATCHEXEC_EVENTS_FILE".into(), path.into());
}
Err(err) => {
error!("Failed to write WATCHEXEC_EVENTS_FILE, continuing without it: {err}");
}
},
EmitEvents::None => {}
}
for (k, v) in add_envs {
debug!(?k, ?v, "inserting environment variable");
command.env(k, v);
}
if let Some(stdin) = stdin {
debug!("set command stdin");
command.stdin(stdin);
}
}
pub(crate) fn reset_screen() {
for cs in [
ClearScreen::WindowsCooked,
ClearScreen::WindowsVt,
ClearScreen::VtLeaveAlt,
ClearScreen::VtWellDone,
ClearScreen::default(),
] {
cs.clear().ok();
}
}

222
crates/cli/src/dirs.rs Normal file
View File

@ -0,0 +1,222 @@
use std::{
collections::HashSet,
path::{Path, PathBuf},
};
use ignore_files::{IgnoreFile, IgnoreFilesFromOriginArgs};
use miette::{miette, IntoDiagnostic, Result};
use project_origins::ProjectType;
use tokio::fs::canonicalize;
use tracing::{debug, info, warn};
use watchexec::paths::common_prefix;
use crate::args::Args;
pub async fn project_origin(args: &Args) -> Result<PathBuf> {
let project_origin = if let Some(origin) = &args.project_origin {
debug!(?origin, "project origin override");
canonicalize(origin).await.into_diagnostic()?
} else {
let homedir = match dirs::home_dir() {
None => None,
Some(dir) => Some(canonicalize(dir).await.into_diagnostic()?),
};
debug!(?homedir, "home directory");
let homedir_requested = homedir.as_ref().map_or(false, |home| {
args.paths
.binary_search_by_key(home, |w| PathBuf::from(w.clone()))
.is_ok()
});
debug!(
?homedir_requested,
"resolved whether the homedir is explicitly requested"
);
let mut origins = HashSet::new();
for path in &args.paths {
origins.extend(project_origins::origins(path).await);
}
match (homedir, homedir_requested) {
(Some(ref dir), false) if origins.contains(dir) => {
debug!("removing homedir from origins");
origins.remove(dir);
}
_ => {}
}
if origins.is_empty() {
debug!("no origins, using current directory");
origins.insert(args.workdir.clone().unwrap());
}
debug!(?origins, "resolved all project origins");
// This canonicalize is probably redundant
canonicalize(
common_prefix(&origins)
.ok_or_else(|| miette!("no common prefix, but this should never fail"))?,
)
.await
.into_diagnostic()?
};
debug!(?project_origin, "resolved common/project origin");
Ok(project_origin)
}
pub async fn vcs_types(origin: &Path) -> Vec<ProjectType> {
let vcs_types = project_origins::types(origin)
.await
.into_iter()
.filter(|pt| pt.is_vcs())
.collect::<Vec<_>>();
info!(?vcs_types, "effective vcs types");
vcs_types
}
pub async fn ignores(args: &Args, vcs_types: &[ProjectType]) -> Result<Vec<IgnoreFile>> {
let origin = args.project_origin.clone().unwrap();
let mut skip_git_global_excludes = false;
let mut ignores = if args.no_project_ignore {
Vec::new()
} else {
let ignore_files = args.ignore_files.iter().map(|path| {
if path.is_absolute() {
path.into()
} else {
origin.join(path)
}
});
let (mut ignores, errors) = ignore_files::from_origin(
IgnoreFilesFromOriginArgs::new_unchecked(
&origin,
args.paths.iter().map(PathBuf::from),
ignore_files,
)
.canonicalise()
.await
.into_diagnostic()?,
)
.await;
for err in errors {
warn!("while discovering project-local ignore files: {}", err);
}
debug!(?ignores, "discovered ignore files from project origin");
if !vcs_types.is_empty() {
ignores = ignores
.into_iter()
.filter(|ig| match ig.applies_to {
Some(pt) if pt.is_vcs() => vcs_types.contains(&pt),
_ => true,
})
.inspect(|ig| {
if let IgnoreFile {
applies_to: Some(ProjectType::Git),
applies_in: None,
..
} = ig
{
warn!("project git config overrides the global excludes");
skip_git_global_excludes = true;
}
})
.collect::<Vec<_>>();
debug!(?ignores, "filtered ignores to only those for project vcs");
}
ignores
};
let global_ignores = if args.no_global_ignore {
Vec::new()
} else {
let (mut global_ignores, errors) = ignore_files::from_environment(Some("watchexec")).await;
for err in errors {
warn!("while discovering global ignore files: {}", err);
}
debug!(?global_ignores, "discovered ignore files from environment");
if skip_git_global_excludes {
global_ignores = global_ignores
.into_iter()
.filter(|gig| {
!matches!(
gig,
IgnoreFile {
applies_to: Some(ProjectType::Git),
applies_in: None,
..
}
)
})
.collect::<Vec<_>>();
debug!(
?global_ignores,
"filtered global ignores to exclude global git ignores"
);
}
global_ignores
};
ignores.extend(global_ignores.into_iter().filter(|ig| match ig.applies_to {
Some(pt) if pt.is_vcs() => vcs_types.contains(&pt),
_ => true,
}));
debug!(
?ignores,
?vcs_types,
"combined and applied overall vcs filter over ignores"
);
ignores.extend(args.ignore_files.iter().map(|ig| IgnoreFile {
applies_to: None,
applies_in: None,
path: ig.clone(),
}));
debug!(
?ignores,
?args.ignore_files,
"combined with ignore files from command line / env"
);
if args.no_project_ignore {
ignores = ignores
.into_iter()
.filter(|ig| {
!ig.applies_in
.as_ref()
.map_or(false, |p| p.starts_with(&origin))
})
.collect::<Vec<_>>();
debug!(
?ignores,
"filtered ignores to exclude project-local ignores"
);
}
if args.no_global_ignore {
ignores = ignores
.into_iter()
.filter(|ig| ig.applies_in.is_some())
.collect::<Vec<_>>();
debug!(?ignores, "filtered ignores to exclude global ignores");
}
if args.no_vcs_ignore {
ignores = ignores
.into_iter()
.filter(|ig| ig.applies_to.is_none())
.collect::<Vec<_>>();
debug!(?ignores, "filtered ignores to exclude VCS-specific ignores");
}
info!(files=?ignores.iter().map(|ig| ig.path.as_path()).collect::<Vec<_>>(), "found some ignores");
Ok(ignores)
}

71
crates/cli/src/emits.rs Normal file
View File

@ -0,0 +1,71 @@
use std::{ffi::OsString, fmt::Write, path::PathBuf};
use miette::{IntoDiagnostic, Result};
use watchexec::paths::summarise_events_to_env;
use watchexec_events::{filekind::FileEventKind, Event, Tag};
use crate::state::RotatingTempFile;
pub fn emits_to_environment(events: &[Event]) -> impl Iterator<Item = (String, OsString)> {
summarise_events_to_env(events.iter())
.into_iter()
.map(|(k, v)| (format!("WATCHEXEC_{k}_PATH"), v))
}
pub fn events_to_simple_format(events: &[Event]) -> Result<String> {
let mut buf = String::new();
for event in events {
let feks = event
.tags
.iter()
.filter_map(|tag| match tag {
Tag::FileEventKind(kind) => Some(kind),
_ => None,
})
.collect::<Vec<_>>();
for path in event.paths().map(|(p, _)| p) {
if feks.is_empty() {
writeln!(&mut buf, "other:{}", path.to_string_lossy()).into_diagnostic()?;
continue;
}
for fek in &feks {
writeln!(
&mut buf,
"{}:{}",
match fek {
FileEventKind::Any | FileEventKind::Other => "other",
FileEventKind::Access(_) => "access",
FileEventKind::Create(_) => "create",
FileEventKind::Modify(_) => "modify",
FileEventKind::Remove(_) => "remove",
},
path.to_string_lossy()
)
.into_diagnostic()?;
}
}
}
Ok(buf)
}
pub fn emits_to_file(target: &RotatingTempFile, events: &[Event]) -> Result<PathBuf> {
target.rotate()?;
target.write(events_to_simple_format(events)?.as_bytes())?;
Ok(target.path())
}
pub fn emits_to_json_file(target: &RotatingTempFile, events: &[Event]) -> Result<PathBuf> {
target.rotate()?;
for event in events {
if event.is_empty() {
continue;
}
target.write(&serde_json::to_vec(event).into_diagnostic()?)?;
target.write(b"\n")?;
}
Ok(target.path())
}

175
crates/cli/src/filterer.rs Normal file
View File

@ -0,0 +1,175 @@
use std::{
ffi::OsString,
path::{Path, PathBuf, MAIN_SEPARATOR},
sync::Arc,
};
use miette::{IntoDiagnostic, Result};
use tokio::io::{AsyncBufReadExt, BufReader};
use tracing::{info, trace, trace_span};
use watchexec::{error::RuntimeError, filter::Filterer};
use watchexec_events::{
filekind::{FileEventKind, ModifyKind},
Event, Priority, Tag,
};
use watchexec_filterer_globset::GlobsetFilterer;
use crate::args::{Args, FsEvent};
pub(crate) mod parse;
mod proglib;
mod progs;
mod syncval;
/// A custom filterer that combines the library's Globset filterer and a switch for --no-meta
#[derive(Debug)]
pub struct WatchexecFilterer {
inner: GlobsetFilterer,
fs_events: Vec<FsEvent>,
progs: Option<progs::FilterProgs>,
}
impl Filterer for WatchexecFilterer {
#[tracing::instrument(level = "trace", skip(self))]
fn check_event(&self, event: &Event, priority: Priority) -> Result<bool, RuntimeError> {
for tag in &event.tags {
if let Tag::FileEventKind(fek) = tag {
let normalised = match fek {
FileEventKind::Access(_) => FsEvent::Access,
FileEventKind::Modify(ModifyKind::Name(_)) => FsEvent::Rename,
FileEventKind::Modify(ModifyKind::Metadata(_)) => FsEvent::Metadata,
FileEventKind::Modify(_) => FsEvent::Modify,
FileEventKind::Create(_) => FsEvent::Create,
FileEventKind::Remove(_) => FsEvent::Remove,
_ => continue,
};
trace!(allowed=?self.fs_events, this=?normalised, "check against fs event filter");
if !self.fs_events.contains(&normalised) {
return Ok(false);
}
}
}
trace!("check against original event");
if !self.inner.check_event(event, priority)? {
return Ok(false);
}
if let Some(progs) = &self.progs {
trace!("check against program filters");
if !progs.check(event)? {
return Ok(false);
}
}
Ok(true)
}
}
impl WatchexecFilterer {
/// Create a new filterer from the given arguments
pub async fn new(args: &Args) -> Result<Arc<Self>> {
let project_origin = args.project_origin.clone().unwrap();
let workdir = args.workdir.clone().unwrap();
let ignore_files = if args.no_discover_ignore {
Vec::new()
} else {
let vcs_types = crate::dirs::vcs_types(&project_origin).await;
crate::dirs::ignores(args, &vcs_types).await?
};
let mut ignores = Vec::new();
if !args.no_default_ignore {
ignores.extend([
(format!("**{MAIN_SEPARATOR}.DS_Store"), None),
(String::from("watchexec.*.log"), None),
(String::from("*.py[co]"), None),
(String::from("#*#"), None),
(String::from(".#*"), None),
(String::from(".*.kate-swp"), None),
(String::from(".*.sw?"), None),
(String::from(".*.sw?x"), None),
(format!("**{MAIN_SEPARATOR}.bzr{MAIN_SEPARATOR}**"), None),
(format!("**{MAIN_SEPARATOR}_darcs{MAIN_SEPARATOR}**"), None),
(
format!("**{MAIN_SEPARATOR}.fossil-settings{MAIN_SEPARATOR}**"),
None,
),
(format!("**{MAIN_SEPARATOR}.git{MAIN_SEPARATOR}**"), None),
(format!("**{MAIN_SEPARATOR}.hg{MAIN_SEPARATOR}**"), None),
(format!("**{MAIN_SEPARATOR}.pijul{MAIN_SEPARATOR}**"), None),
(format!("**{MAIN_SEPARATOR}.svn{MAIN_SEPARATOR}**"), None),
]);
}
let mut filters = args
.filter_patterns
.iter()
.map(|f| (f.to_owned(), Some(workdir.clone())))
.collect::<Vec<_>>();
for filter_file in &args.filter_files {
filters.extend(read_filter_file(filter_file).await?);
}
ignores.extend(
args.ignore_patterns
.iter()
.map(|f| (f.to_owned(), Some(workdir.clone()))),
);
let exts = args
.filter_extensions
.iter()
.map(|e| OsString::from(e.strip_prefix('.').unwrap_or(e)));
info!("initialising Globset filterer");
Ok(Arc::new(Self {
inner: GlobsetFilterer::new(project_origin, filters, ignores, ignore_files, exts)
.await
.into_diagnostic()?,
fs_events: args.filter_fs_events.clone(),
progs: if args.filter_programs_parsed.is_empty() {
None
} else {
Some(progs::FilterProgs::new(args)?)
},
}))
}
}
async fn read_filter_file(path: &Path) -> Result<Vec<(String, Option<PathBuf>)>> {
let _span = trace_span!("loading filter file", ?path).entered();
let file = tokio::fs::File::open(path).await.into_diagnostic()?;
let metadata_len = file
.metadata()
.await
.map(|m| usize::try_from(m.len()))
.unwrap_or(Ok(0))
.into_diagnostic()?;
let filter_capacity = if metadata_len == 0 {
0
} else {
metadata_len / 20
};
let mut filters = Vec::with_capacity(filter_capacity);
let reader = BufReader::new(file);
let mut lines = reader.lines();
while let Some(line) = lines.next_line().await.into_diagnostic()? {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
trace!(?line, "adding filter line");
filters.push((line.to_owned(), Some(path.to_owned())));
}
Ok(filters)
}

View File

@ -0,0 +1,17 @@
use miette::{miette, Result};
pub fn parse_filter_program((n, prog): (usize, String)) -> Result<jaq_syn::Main> {
let parser = jaq_parse::main();
let (main, errs) = jaq_parse::parse(&prog, parser);
if !errs.is_empty() {
let errs = errs
.into_iter()
.map(|err| err.to_string())
.collect::<Vec<_>>()
.join("\n");
return Err(miette!("{}", errs).wrap_err(format!("failed to load filter program #{}", n)));
}
main.ok_or_else(|| miette!("failed to load filter program #{} (no reason given)", n))
}

View File

@ -0,0 +1,27 @@
use jaq_interpret::ParseCtx;
use miette::Result;
use tracing::debug;
mod file;
mod hash;
mod kv;
mod macros;
mod output;
pub fn jaq_lib() -> Result<ParseCtx> {
let mut jaq = ParseCtx::new(Vec::new());
debug!("loading jaq core library");
jaq.insert_natives(jaq_core::core());
debug!("loading jaq std library");
jaq.insert_defs(jaq_std::std());
debug!("loading jaq watchexec library");
file::load(&mut jaq);
hash::load(&mut jaq);
kv::load(&mut jaq);
output::load(&mut jaq);
Ok(jaq)
}

View File

@ -0,0 +1,173 @@
use std::{
fs::{metadata, File, FileType, Metadata},
io::{BufReader, Read},
iter::once,
time::{SystemTime, UNIX_EPOCH},
};
use jaq_interpret::{Error, Native, ParseCtx, Val};
use serde_json::{json, Value};
use tracing::{debug, error, trace};
use super::macros::*;
pub fn load(jaq: &mut ParseCtx) {
trace!("jaq: add file_read filter");
jaq.insert_native(
"file_read".into(),
1,
Native::new({
move |args, (ctx, val)| {
let path = match &val {
Val::Str(v) => v.to_string(),
_ => return_err!(Err(Error::str("expected string (path) but got {val:?}"))),
};
let bytes = match int_arg!(args, 0, ctx, &val) {
Ok(v) => v,
Err(e) => return_err!(Err(e)),
};
Box::new(once(Ok(match File::open(&path) {
Ok(file) => {
let buf_reader = BufReader::new(file);
let mut limited = buf_reader.take(bytes);
let mut buffer = String::with_capacity(bytes as _);
match limited.read_to_string(&mut buffer) {
Ok(read) => {
debug!("jaq: read {read} bytes from {path:?}");
Val::Str(buffer.into())
}
Err(err) => {
error!("jaq: failed to read from {path:?}: {err:?}");
Val::Null
}
}
}
Err(err) => {
error!("jaq: failed to open file {path:?}: {err:?}");
Val::Null
}
})))
}
}),
);
trace!("jaq: add file_meta filter");
jaq.insert_native(
"file_meta".into(),
0,
Native::new({
move |_, (_, val)| {
let path = match &val {
Val::Str(v) => v.to_string(),
_ => return_err!(Err(Error::str("expected string (path) but got {val:?}"))),
};
Box::new(once(Ok(match metadata(&path) {
Ok(meta) => Val::from(json_meta(meta)),
Err(err) => {
error!("jaq: failed to open {path:?}: {err:?}");
Val::Null
}
})))
}
}),
);
trace!("jaq: add file_size filter");
jaq.insert_native(
"file_size".into(),
0,
Native::new({
move |_, (_, val)| {
let path = match &val {
Val::Str(v) => v.to_string(),
_ => return_err!(Err(Error::str("expected string (path) but got {val:?}"))),
};
Box::new(once(Ok(match metadata(&path) {
Ok(meta) => Val::Int(meta.len() as _),
Err(err) => {
error!("jaq: failed to open {path:?}: {err:?}");
Val::Null
}
})))
}
}),
);
}
fn json_meta(meta: Metadata) -> Value {
let perms = meta.permissions();
let mut val = json!({
"type": filetype_str(meta.file_type()),
"size": meta.len(),
"modified": fs_time(meta.modified()),
"accessed": fs_time(meta.accessed()),
"created": fs_time(meta.created()),
"dir": meta.is_dir(),
"file": meta.is_file(),
"symlink": meta.is_symlink(),
"readonly": perms.readonly(),
});
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let map = val.as_object_mut().unwrap();
map.insert(
"mode".to_string(),
Value::String(format!("{:o}", perms.mode())),
);
map.insert("mode_byte".to_string(), Value::from(perms.mode()));
map.insert(
"executable".to_string(),
Value::Bool(perms.mode() & 0o111 != 0),
);
}
val
}
fn filetype_str(filetype: FileType) -> &'static str {
#[cfg(unix)]
{
use std::os::unix::fs::FileTypeExt;
if filetype.is_char_device() {
return "char";
} else if filetype.is_block_device() {
return "block";
} else if filetype.is_fifo() {
return "fifo";
} else if filetype.is_socket() {
return "socket";
}
}
#[cfg(windows)]
{
use std::os::windows::fs::FileTypeExt;
if filetype.is_symlink_dir() {
return "symdir";
} else if filetype.is_symlink_file() {
return "symfile";
}
}
if filetype.is_dir() {
"dir"
} else if filetype.is_file() {
"file"
} else if filetype.is_symlink() {
"symlink"
} else {
"unknown"
}
}
fn fs_time(time: std::io::Result<SystemTime>) -> Option<u64> {
time.ok()
.and_then(|time| time.duration_since(UNIX_EPOCH).ok())
.map(|dur| dur.as_secs())
}

View File

@ -0,0 +1,62 @@
use std::{fs::File, io::Read, iter::once};
use jaq_interpret::{Error, Native, ParseCtx, Val};
use tracing::{debug, error, trace};
use super::macros::*;
pub fn load(jaq: &mut ParseCtx) {
trace!("jaq: add hash filter");
jaq.insert_native(
"hash".into(),
0,
Native::new({
move |_, (_, val)| {
let string = match &val {
Val::Str(v) => v.to_string(),
_ => return_err!(Err(Error::str("expected string but got {val:?}"))),
};
Box::new(once(Ok(Val::Str(
blake3::hash(string.as_bytes()).to_hex().to_string().into(),
))))
}
}),
);
trace!("jaq: add file_hash filter");
jaq.insert_native(
"file_hash".into(),
0,
Native::new({
move |_, (_, val)| {
let path = match &val {
Val::Str(v) => v.to_string(),
_ => return_err!(Err(Error::str("expected string but got {val:?}"))),
};
Box::new(once(Ok(match File::open(&path) {
Ok(mut file) => {
const BUFFER_SIZE: usize = 1024 * 1024;
let mut hasher = blake3::Hasher::new();
let mut buf = vec![0; BUFFER_SIZE];
while let Ok(bytes) = file.read(&mut buf) {
debug!("jaq: read {bytes} bytes from {path:?}");
if bytes == 0 {
break;
}
hasher.update(&buf[..bytes]);
buf = vec![0; BUFFER_SIZE];
}
Val::Str(hasher.finalize().to_hex().to_string().into())
}
Err(err) => {
error!("jaq: failed to open file {path:?}: {err:?}");
Val::Null
}
})))
}
}),
);
}

View File

@ -0,0 +1,69 @@
use std::{iter::once, sync::Arc};
use dashmap::DashMap;
use jaq_interpret::{Error, Native, ParseCtx, Val};
use once_cell::sync::OnceCell;
use tracing::trace;
use crate::filterer::syncval::SyncVal;
use super::macros::*;
type KvStore = Arc<DashMap<String, SyncVal>>;
fn kv_store() -> KvStore {
static KV_STORE: OnceCell<KvStore> = OnceCell::new();
KV_STORE.get_or_init(|| KvStore::default()).clone()
}
pub fn load(jaq: &mut ParseCtx) {
trace!("jaq: add kv_clear filter");
jaq.insert_native(
"kv_clear".into(),
0,
Native::new({
move |_, (_, val)| {
let kv = kv_store();
kv.clear();
Box::new(once(Ok(val)))
}
}),
);
trace!("jaq: add kv_store filter");
jaq.insert_native(
"kv_store".into(),
1,
Native::new({
move |args, (ctx, val)| {
let kv = kv_store();
let key = match string_arg!(args, 0, ctx, val) {
Ok(v) => v,
Err(e) => return_err!(Err(e)),
};
kv.insert(key, (&val).into());
Box::new(once(Ok(val)))
}
}),
);
trace!("jaq: add kv_fetch filter");
jaq.insert_native(
"kv_fetch".into(),
1,
Native::new({
move |args, (ctx, val)| {
let kv = kv_store();
let key = match string_arg!(args, 0, ctx, val) {
Ok(v) => v,
Err(e) => return_err!(Err(e)),
};
Box::new(once(Ok(kv
.get(&key)
.map(|val| val.value().into())
.unwrap_or(Val::Null))))
}
}),
);
}

View File

@ -0,0 +1,30 @@
macro_rules! return_err {
($err:expr) => {
return Box::new(once($err))
};
}
pub(crate) use return_err;
macro_rules! string_arg {
($args:expr, $n:expr, $ctx:expr, $val:expr) => {
match ::jaq_interpret::FilterT::run($args.get($n), ($ctx.clone(), $val.clone())).next() {
Some(Ok(Val::Str(v))) => Ok(v.to_string()),
Some(Ok(val)) => Err(Error::str(format!("expected string but got {val:?}"))),
Some(Err(e)) => Err(e),
None => Err(Error::str("value expected but none found")),
}
};
}
pub(crate) use string_arg;
macro_rules! int_arg {
($args:expr, $n:expr, $ctx:expr, $val:expr) => {
match ::jaq_interpret::FilterT::run($args.get($n), ($ctx.clone(), $val.clone())).next() {
Some(Ok(Val::Int(v))) => Ok(v as _),
Some(Ok(val)) => Err(Error::str(format!("expected int but got {val:?}"))),
Some(Err(e)) => Err(e),
None => Err(Error::str("value expected but none found")),
}
};
}
pub(crate) use int_arg;

View File

@ -0,0 +1,83 @@
use std::iter::once;
use jaq_interpret::{Error, Native, ParseCtx, Val};
use tracing::{debug, error, info, trace, warn};
use super::macros::*;
macro_rules! log_action {
($level:expr, $val:expr) => {
match $level.to_ascii_lowercase().as_str() {
"trace" => trace!("jaq: {}", $val),
"debug" => debug!("jaq: {}", $val),
"info" => info!("jaq: {}", $val),
"warn" => warn!("jaq: {}", $val),
"error" => error!("jaq: {}", $val),
_ => return_err!(Err(Error::str("invalid log level"))),
}
};
}
pub fn load(jaq: &mut ParseCtx) {
trace!("jaq: add log filter");
jaq.insert_native(
"log".into(),
1,
Native::with_update(
|args, (ctx, val)| {
let level = match string_arg!(args, 0, ctx, val) {
Ok(v) => v,
Err(e) => return_err!(Err(e)),
};
log_action!(level, val);
// passthrough
Box::new(once(Ok(val)))
},
|args, (ctx, val), _| {
let level = match string_arg!(args, 0, ctx, val) {
Ok(v) => v,
Err(e) => return_err!(Err(e)),
};
log_action!(level, val);
// passthrough
Box::new(once(Ok(val)))
},
),
);
trace!("jaq: add printout filter");
jaq.insert_native(
"printout".into(),
0,
Native::with_update(
|_, (_, val)| {
println!("{}", val);
Box::new(once(Ok(val)))
},
|_, (_, val), _| {
println!("{}", val);
Box::new(once(Ok(val)))
},
),
);
trace!("jaq: add printerr filter");
jaq.insert_native(
"printerr".into(),
0,
Native::with_update(
|_, (_, val)| {
eprintln!("{}", val);
Box::new(once(Ok(val)))
},
|_, (_, val), _| {
eprintln!("{}", val);
Box::new(once(Ok(val)))
},
),
);
}

View File

@ -0,0 +1,143 @@
use std::{iter::empty, marker::PhantomData};
use jaq_interpret::{Ctx, FilterT, RcIter, Val};
use miette::miette;
use tokio::{
sync::{mpsc, oneshot},
task::{block_in_place, spawn_blocking},
};
use tracing::{error, trace, warn};
use watchexec::error::RuntimeError;
use watchexec_events::Event;
use crate::args::Args;
const BUFFER: usize = 128;
#[derive(Debug)]
pub struct FilterProgs {
channel: Requester<Event, bool>,
}
#[derive(Debug, Clone)]
pub struct Requester<S, R> {
sender: mpsc::Sender<(S, oneshot::Sender<R>)>,
_receiver: PhantomData<R>,
}
impl<S, R> Requester<S, R>
where
S: Send + Sync,
R: Send + Sync,
{
pub fn new(capacity: usize) -> (Self, mpsc::Receiver<(S, oneshot::Sender<R>)>) {
let (sender, receiver) = mpsc::channel(capacity);
(
Self {
sender,
_receiver: PhantomData,
},
receiver,
)
}
pub fn call(&self, value: S) -> Result<R, RuntimeError> {
// FIXME: this should really be async with a timeout, but that needs filtering in general
// to be async, which should be done at some point
block_in_place(|| {
let (sender, receiver) = oneshot::channel();
self.sender.blocking_send((value, sender)).map_err(|err| {
RuntimeError::External(miette!("filter progs internal channel: {}", err).into())
})?;
receiver
.blocking_recv()
.map_err(|err| RuntimeError::External(Box::new(err)))
})
}
}
impl FilterProgs {
pub fn check(&self, event: &Event) -> Result<bool, RuntimeError> {
self.channel.call(event.clone())
}
pub fn new(args: &Args) -> miette::Result<Self> {
let progs = args.filter_programs_parsed.clone();
eprintln!(
"EXPERIMENTAL: filter programs are unstable and may change/vanish without notice"
);
let (requester, mut receiver) = Requester::<Event, bool>::new(BUFFER);
let task =
spawn_blocking(move || {
'chan: while let Some((event, sender)) = receiver.blocking_recv() {
let val = serde_json::to_value(&event)
.map_err(|err| miette!("failed to serialize event: {}", err))
.map(Val::from)?;
for (n, prog) in progs.iter().enumerate() {
trace!(?n, "trying filter program");
let mut jaq = super::proglib::jaq_lib()?;
let filter = jaq.compile(prog.clone());
if !jaq.errs.is_empty() {
for (error, span) in jaq.errs {
error!(%error, "failed to compile filter program #{n}@{}:{}", span.start, span.end);
}
continue;
}
let inputs = RcIter::new(empty());
let mut results = filter.run((Ctx::new([], &inputs), val.clone()));
if let Some(res) = results.next() {
match res {
Ok(Val::Bool(false)) => {
trace!(
?n,
verdict = false,
"filter program finished; fail so stopping there"
);
sender
.send(false)
.unwrap_or_else(|_| warn!("failed to send filter result"));
continue 'chan;
}
Ok(Val::Bool(true)) => {
trace!(
?n,
verdict = true,
"filter program finished; pass so trying next"
);
continue;
}
Ok(val) => {
error!(?n, ?val, "filter program returned non-boolean, ignoring and trying next");
continue;
}
Err(err) => {
error!(?n, error=%err, "filter program failed, so trying next");
continue;
}
}
}
}
trace!("all filters failed, sending pass as default");
sender
.send(true)
.unwrap_or_else(|_| warn!("failed to send filter result"));
}
Ok(()) as miette::Result<()>
});
tokio::spawn(async {
match task.await {
Ok(Ok(())) => {}
Ok(Err(err)) => error!("filter progs task failed: {}", err),
Err(err) => error!("filter progs task panicked: {}", err),
}
});
Ok(Self { channel: requester })
}
}

View File

@ -0,0 +1,71 @@
/// Jaq's [Val](jaq_interpret::Val) uses Rc, but we want to use in Sync contexts. UGH!
use std::{rc::Rc, sync::Arc};
use indexmap::IndexMap;
use jaq_interpret::Val;
#[derive(Clone, Debug)]
pub enum SyncVal {
Null,
Bool(bool),
Int(isize),
Float(f64),
Num(Arc<str>),
Str(Arc<str>),
Arr(Arc<[SyncVal]>),
Obj(Arc<IndexMap<Arc<str>, SyncVal>>),
}
impl From<&Val> for SyncVal {
fn from(val: &Val) -> Self {
match val {
Val::Null => Self::Null,
Val::Bool(b) => Self::Bool(*b),
Val::Int(i) => Self::Int(*i),
Val::Float(f) => Self::Float(*f),
Val::Num(s) => Self::Num(s.to_string().into()),
Val::Str(s) => Self::Str(s.to_string().into()),
Val::Arr(a) => Self::Arr({
let mut arr = Vec::with_capacity(a.len());
for v in a.iter() {
arr.push(v.into());
}
arr.into()
}),
Val::Obj(m) => Self::Obj(Arc::new({
let mut map = IndexMap::new();
for (k, v) in m.iter() {
map.insert(k.to_string().into(), v.into());
}
map
})),
}
}
}
impl From<&SyncVal> for Val {
fn from(val: &SyncVal) -> Self {
match val {
SyncVal::Null => Self::Null,
SyncVal::Bool(b) => Self::Bool(*b),
SyncVal::Int(i) => Self::Int(*i),
SyncVal::Float(f) => Self::Float(*f),
SyncVal::Num(s) => Self::Num(s.to_string().into()),
SyncVal::Str(s) => Self::Str(s.to_string().into()),
SyncVal::Arr(a) => Self::Arr({
let mut arr = Vec::with_capacity(a.len());
for v in a.iter() {
arr.push(v.into());
}
arr.into()
}),
SyncVal::Obj(m) => Self::Obj(Rc::new({
let mut map: IndexMap<_, _, ahash::RandomState> = Default::default();
for (k, v) in m.iter() {
map.insert(k.to_string().into(), v.into());
}
map
})),
}
}
}

128
crates/cli/src/lib.rs Normal file
View File

@ -0,0 +1,128 @@
#![deny(rust_2018_idioms)]
#![allow(clippy::missing_const_for_fn, clippy::future_not_send)]
use std::{io::Write, process::Stdio};
use args::{Args, ShellCompletion};
use clap::CommandFactory;
use clap_complete::{Generator, Shell};
use clap_mangen::Man;
use is_terminal::IsTerminal;
use miette::{IntoDiagnostic, Result};
use tokio::{io::AsyncWriteExt, process::Command};
use tracing::{debug, info};
use watchexec::Watchexec;
use watchexec_events::{Event, Priority};
use crate::filterer::WatchexecFilterer;
pub mod args;
mod config;
mod dirs;
mod emits;
mod filterer;
mod state;
async fn run_watchexec(args: Args) -> Result<()> {
info!(version=%env!("CARGO_PKG_VERSION"), "constructing Watchexec from CLI");
let state = state::State::default();
let config = config::make_config(&args, &state)?;
config.filterer(WatchexecFilterer::new(&args).await?);
info!("initialising Watchexec runtime");
let wx = Watchexec::with_config(config)?;
if !args.postpone {
debug!("kicking off with empty event");
wx.send_event(Event::default(), Priority::Urgent).await?;
}
info!("running main loop");
wx.main().await.into_diagnostic()??;
if matches!(args.screen_clear, Some(args::ClearMode::Reset)) {
config::reset_screen();
}
info!("done with main loop");
Ok(())
}
async fn run_manpage(_args: Args) -> Result<()> {
info!(version=%env!("CARGO_PKG_VERSION"), "constructing manpage");
let man = Man::new(Args::command().long_version(None));
let mut buffer: Vec<u8> = Default::default();
man.render(&mut buffer).into_diagnostic()?;
if std::io::stdout().is_terminal() && which::which("man").is_ok() {
let mut child = Command::new("man")
.arg("-l")
.arg("-")
.stdin(Stdio::piped())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.kill_on_drop(true)
.spawn()
.into_diagnostic()?;
child
.stdin
.as_mut()
.unwrap()
.write_all(&buffer)
.await
.into_diagnostic()?;
if let Some(code) = child
.wait()
.await
.into_diagnostic()?
.code()
.and_then(|code| if code == 0 { None } else { Some(code) })
{
return Err(miette::miette!("Exited with status code {}", code));
}
} else {
std::io::stdout()
.lock()
.write_all(&buffer)
.into_diagnostic()?;
}
Ok(())
}
#[allow(clippy::unused_async)]
async fn run_completions(shell: ShellCompletion) -> Result<()> {
fn generate(generator: impl Generator) {
let mut cmd = Args::command();
clap_complete::generate(generator, &mut cmd, "watchexec", &mut std::io::stdout());
}
info!(version=%env!("CARGO_PKG_VERSION"), "constructing completions");
match shell {
ShellCompletion::Bash => generate(Shell::Bash),
ShellCompletion::Elvish => generate(Shell::Elvish),
ShellCompletion::Fish => generate(Shell::Fish),
ShellCompletion::Nu => generate(clap_complete_nushell::Nushell),
ShellCompletion::Powershell => generate(Shell::PowerShell),
ShellCompletion::Zsh => generate(Shell::Zsh),
}
Ok(())
}
pub async fn run() -> Result<()> {
let (args, _log_guard) = args::get_args().await?;
if args.manual {
run_manpage(args).await
} else if let Some(shell) = args.completions {
run_completions(shell).await
} else {
run_watchexec(args).await
}
}

22
crates/cli/src/main.rs Normal file
View File

@ -0,0 +1,22 @@
#[cfg(feature = "eyra")]
extern crate eyra;
use miette::IntoDiagnostic;
#[cfg(target_env = "musl")]
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
fn main() -> miette::Result<()> {
#[cfg(feature = "pid1")]
pid1::Pid1Settings::new()
.enable_log(cfg!(feature = "pid1-withlog"))
.launch()
.into_diagnostic()?;
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async { watchexec_cli::run().await })
}

48
crates/cli/src/state.rs Normal file
View File

@ -0,0 +1,48 @@
use std::{
env::var_os,
io::Write,
path::PathBuf,
sync::{Arc, Mutex},
};
use miette::{IntoDiagnostic, Result};
use tempfile::NamedTempFile;
#[derive(Clone, Debug, Default)]
pub struct State {
pub emit_file: RotatingTempFile,
}
#[derive(Clone, Debug, Default)]
pub struct RotatingTempFile(Arc<Mutex<Option<NamedTempFile>>>);
impl RotatingTempFile {
pub fn rotate(&self) -> Result<()> {
// implicitly drops the old file
*self.0.lock().unwrap() = Some(
if let Some(dir) = var_os("WATCHEXEC_TMPDIR") {
NamedTempFile::new_in(dir)
} else {
NamedTempFile::new()
}
.into_diagnostic()?,
);
Ok(())
}
pub fn write(&self, data: &[u8]) -> Result<()> {
if let Some(file) = self.0.lock().unwrap().as_mut() {
file.write_all(data).into_diagnostic()?;
}
Ok(())
}
pub fn path(&self) -> PathBuf {
if let Some(file) = self.0.lock().unwrap().as_ref() {
file.path().to_owned()
} else {
PathBuf::new()
}
}
}

View File

@ -0,0 +1,121 @@
use std::path::PathBuf;
use std::{fs, sync::OnceLock};
use miette::{Context, IntoDiagnostic, Result};
use rand::Rng;
static PLACEHOLDER_DATA: OnceLock<String> = OnceLock::new();
fn get_placeholder_data() -> &'static str {
PLACEHOLDER_DATA.get_or_init(|| "PLACEHOLDER\n".repeat(500))
}
/// The amount of nesting that will be used for generated files
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum GeneratedFileNesting {
/// Only one level of files
Flat,
/// Random, up to a certiain maximum
RandomToMax(usize),
}
/// Configuration for creating testing subfolders
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct TestSubfolderConfiguration {
/// The amount of nesting that will be used when folders are generated
pub(crate) nesting: GeneratedFileNesting,
/// Number of files the folder should contain
pub(crate) file_count: usize,
/// Subfolder name
pub(crate) name: String,
}
/// Options for generating test files
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub(crate) struct GenerateTestFilesArgs {
/// The path where the files should be generated
/// if None, the current working directory will be used.
pub(crate) path: Option<PathBuf>,
/// Configurations for subfolders to generate
pub(crate) subfolder_configs: Vec<TestSubfolderConfiguration>,
}
/// Generate test files
///
/// This returns the same number of paths that were requested via subfolder_configs.
pub(crate) fn generate_test_files(args: GenerateTestFilesArgs) -> Result<Vec<PathBuf>> {
// Use or create a temporary directory for the test files
let tmpdir = if let Some(p) = args.path {
p
} else {
tempfile::tempdir()
.into_diagnostic()
.wrap_err("failed to build tempdir")?
.into_path()
};
let mut paths = vec![tmpdir.clone()];
// Generate subfolders matching each config
for subfolder_config in args.subfolder_configs.iter() {
// Create the subfolder path
let subfolder_path = tmpdir.join(&subfolder_config.name);
fs::create_dir(&subfolder_path)
.into_diagnostic()
.wrap_err(format!(
"failed to create path for dir [{}]",
subfolder_path.display()
))?;
paths.push(subfolder_path.clone());
// Fill the subfolder with files
match subfolder_config.nesting {
GeneratedFileNesting::Flat => {
for idx in 0..subfolder_config.file_count {
// Write stub file contents
fs::write(
subfolder_path.join(format!("stub-file-{idx}")),
get_placeholder_data(),
)
.into_diagnostic()
.wrap_err(format!(
"failed to write temporary file in subfolder {} @ idx {idx}",
subfolder_path.display()
))?;
}
}
GeneratedFileNesting::RandomToMax(max_depth) => {
let mut generator = rand::thread_rng();
for idx in 0..subfolder_config.file_count {
// Build a randomized path up to max depth
let mut generated_path = subfolder_path.clone();
let depth = generator.gen_range(0..max_depth);
for _ in 0..depth {
generated_path.push("stub-dir");
}
// Create the path
fs::create_dir_all(&generated_path)
.into_diagnostic()
.wrap_err(format!(
"failed to create randomly generated path [{}]",
generated_path.display()
))?;
// Write stub file contents @ the new randomized path
fs::write(
generated_path.join(format!("stub-file-{idx}")),
get_placeholder_data(),
)
.into_diagnostic()
.wrap_err(format!(
"failed to write temporary file in subfolder {} @ idx {idx}",
subfolder_path.display()
))?;
}
}
}
}
Ok(paths)
}

146
crates/cli/tests/ignore.rs Normal file
View File

@ -0,0 +1,146 @@
use std::{
path::{Path, PathBuf},
process::Stdio,
time::Duration,
};
use miette::{IntoDiagnostic, Result, WrapErr};
use tokio::{process::Command, time::Instant};
use tracing_test::traced_test;
use uuid::Uuid;
mod common;
use common::{generate_test_files, GenerateTestFilesArgs};
use crate::common::{GeneratedFileNesting, TestSubfolderConfiguration};
/// Directory name that will be sued for the dir that *should* be watched
const WATCH_DIR_NAME: &str = "watch";
/// The token that watch will echo every time a match is found
const WATCH_TOKEN: &str = "updated";
/// Ensure that watchexec runtime does not increase with the
/// number of *ignored* files in a given folder
///
/// This test creates two separate folders, one small and the other large
///
/// Each folder has two subfolders:
/// - a shallow one to be watched, with a few files of single depth (20 files)
/// - a deep one to be ignored, with many files at varying depths (small case 200 files, large case 200,000 files)
///
/// watchexec, when executed on *either* folder should *not* experience a more
/// than 10x degradation in performance, because the vast majority of the files
/// are supposed to be ignored to begin with.
///
/// When running the CLI on the root folders, it should *not* take a long time to start de
#[tokio::test]
#[traced_test]
async fn e2e_ignore_many_files_200_000() -> Result<()> {
// Create a tempfile so that drop will clean it up
let small_test_dir = tempfile::tempdir()
.into_diagnostic()
.wrap_err("failed to create tempdir for test use")?;
// Determine the watchexec bin to use & build arguments
let wexec_bin = std::env::var("TEST_WATCHEXEC_BIN").unwrap_or(
option_env!("CARGO_BIN_EXE_watchexec")
.map(std::string::ToString::to_string)
.unwrap_or("watchexec".into()),
);
let token = format!("{WATCH_TOKEN}-{}", Uuid::new_v4());
let args: Vec<String> = vec![
"-1".into(), // exit as soon as watch completes
"--watch".into(),
WATCH_DIR_NAME.into(),
"echo".into(),
token.clone(),
];
// Generate a small directory of files containing dirs that *will* and will *not* be watched
let [ref root_dir_path, _, _] = generate_test_files(GenerateTestFilesArgs {
path: Some(PathBuf::from(small_test_dir.path())),
subfolder_configs: vec![
// Shallow folder will have a small number of files and won't be watched
TestSubfolderConfiguration {
name: "watch".into(),
nesting: GeneratedFileNesting::Flat,
file_count: 5,
},
// Deep folder will have *many* amll files and will be watched
TestSubfolderConfiguration {
name: "unrelated".into(),
nesting: GeneratedFileNesting::RandomToMax(42),
file_count: 200,
},
],
})?[..] else {
panic!("unexpected number of paths returned from generate_test_files");
};
// Get the number of elapsed
let small_elapsed = run_watchexec_cmd(&wexec_bin, root_dir_path, args.clone()).await?;
// Create a tempfile so that drop will clean it up
let large_test_dir = tempfile::tempdir()
.into_diagnostic()
.wrap_err("failed to create tempdir for test use")?;
// Generate a *large* directory of files
let [ref root_dir_path, _, _] = generate_test_files(GenerateTestFilesArgs {
path: Some(PathBuf::from(large_test_dir.path())),
subfolder_configs: vec![
// Shallow folder will have a small number of files and won't be watched
TestSubfolderConfiguration {
name: "watch".into(),
nesting: GeneratedFileNesting::Flat,
file_count: 5,
},
// Deep folder will have *many* amll files and will be watched
TestSubfolderConfiguration {
name: "unrelated".into(),
nesting: GeneratedFileNesting::RandomToMax(42),
file_count: 200_000,
},
],
})?[..] else {
panic!("unexpected number of paths returned from generate_test_files");
};
// Get the number of elapsed
let large_elapsed = run_watchexec_cmd(&wexec_bin, root_dir_path, args.clone()).await?;
// We expect the ignores to not impact watchexec startup time at all
// whether there are 200 files in there or 200k
assert!(
large_elapsed < small_elapsed * 10,
"200k ignore folder ({:?}) took more than 10x more time ({:?}) than 200 ignore folder ({:?})",
large_elapsed,
small_elapsed * 10,
small_elapsed,
);
Ok(())
}
/// Run a watchexec command once
async fn run_watchexec_cmd(
wexec_bin: impl AsRef<str>,
dir: impl AsRef<Path>,
args: impl Into<Vec<String>>,
) -> Result<Duration> {
// Build the subprocess command
let mut cmd = Command::new(wexec_bin.as_ref());
cmd.args(args.into());
cmd.current_dir(dir);
cmd.stdout(Stdio::piped());
cmd.stderr(Stdio::piped());
let start = Instant::now();
cmd.kill_on_drop(true)
.output()
.await
.into_diagnostic()
.wrap_err("fixed")?;
Ok(start.elapsed())
}

View File

@ -0,0 +1,2 @@
#define RT_MANIFEST 24
1 RT_MANIFEST "watchexec.exe.manifest"

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="Watchexec.Cli.watchexec"
version="2.1.1.0"
/>
<trustInfo>
<security>
<!--
UAC settings:
- app should run at same integrity level as calling process
- app does not need to manipulate windows belonging to
higher-integrity-level processes
-->
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10, 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws="http://schemas.microsoft.com/SMI/2020/WindowsSettings">
<ws:longPathAware xmlns:ws="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</ws:longPathAware>
<ws:activeCodePage xmlns:ws="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</ws:activeCodePage>
<ws:heapType xmlns:ws="http://schemas.microsoft.com/SMI/2020/WindowsSettings">SegmentHeap</ws:heapType>
</windowsSettings>
</application>
</assembly>

View File

@ -0,0 +1,27 @@
# Changelog
## Next (YYYY-MM-DD)
## v3.0.0 (2024-04-20)
- Deps: nix 0.28
## v2.0.1 (2023-11-29)
- Add `ProcessEnd::into_exitstatus` testing-only utility method.
- Deps: upgrade to Notify 6.0
- Deps: upgrade to nix 0.27
- Deps: upgrade to watchexec-signals 2.0.0
## v2.0.0 (2023-11-29)
Same as 2.0.1, but yanked.
## v1.1.0 (2023-11-26)
Same as 2.0.1, but yanked.
## v1.0.0 (2023-03-18)
- Split off new `watchexec-events` crate (this one), to have a lightweight library that can parse
and generate events and maintain the JSON event format.

42
crates/events/Cargo.toml Normal file
View File

@ -0,0 +1,42 @@
[package]
name = "watchexec-events"
version = "3.0.0"
authors = ["Félix Saparelli <felix@passcod.name>"]
license = "Apache-2.0 OR MIT"
description = "Watchexec's event types"
keywords = ["watchexec", "event", "format", "json"]
documentation = "https://docs.rs/watchexec-events"
repository = "https://github.com/watchexec/watchexec"
readme = "README.md"
rust-version = "1.61.0"
edition = "2021"
[dependencies.notify]
version = "6.0.0"
optional = true
[dependencies.serde]
version = "1.0.183"
optional = true
features = ["derive"]
[dependencies.watchexec-signals]
version = "3.0.0"
path = "../signals"
default-features = false
[target.'cfg(unix)'.dependencies.nix]
version = "0.28.0"
features = ["signal"]
[dev-dependencies]
snapbox = "0.5.9"
serde_json = "1.0.107"
[features]
default = ["notify"]
notify = ["dep:notify"]
serde = ["dep:serde", "notify?/serde", "watchexec-signals/serde"]

42
crates/events/README.md Normal file
View File

@ -0,0 +1,42 @@
# watchexec-events
_Watchexec's event types._
- **[API documentation][docs]**.
- Licensed under [Apache 2.0][license] or [MIT](https://passcod.mit-license.org).
- Status: maintained.
[docs]: https://docs.rs/watchexec-events
[license]: ../../LICENSE
Fundamentally, events in watchexec have three purposes:
1. To trigger the launch, restart, or other interruption of a process;
2. To be filtered upon according to whatever set of criteria is desired;
3. To carry information about what caused the event, which may be provided to the process.
Outside of Watchexec, this library is particularly useful if you're building a tool that runs under
it, and want to easily read its events (with `--emit-events-to=json-file` and `--emit-events-to=json-stdio`).
```rust ,no_run
use std::io::{stdin, Result};
use watchexec_events::Event;
fn main() -> Result<()> {
for line in stdin().lines() {
let event: Event = serde_json::from_str(&line?)?;
dbg!(event);
}
Ok(())
}
```
## Features
- `serde`: enables serde support.
- `notify`: use Notify's file event types (default).
If you disable `notify`, you'll get a leaner dependency tree that's still able to parse the entire
events, but isn't type compatible with Notify. In most deserialisation usecases, this is fine, but
it's not the default to avoid surprises.

View File

@ -0,0 +1,11 @@
use std::io::{stdin, Result};
use watchexec_events::Event;
fn main() -> Result<()> {
for line in stdin().lines() {
let event: Event = serde_json::from_str(&line?)?;
dbg!(event);
}
Ok(())
}

Some files were not shown because too many files have changed in this diff Show More