mirror of
https://github.com/watchexec/watchexec.git
synced 2024-09-30 07:01:34 +02:00
Compare commits
No commits in common. "main" and "watchexec-v4.0.0" have entirely different histories.
main
...
watchexec-
1
.github/workflows/dist-manifest.jq
vendored
1
.github/workflows/dist-manifest.jq
vendored
@ -4,6 +4,7 @@
|
|||||||
app_name: "watchexec",
|
app_name: "watchexec",
|
||||||
app_version: $version,
|
app_version: $version,
|
||||||
changelog_title: "CLI \($version)",
|
changelog_title: "CLI \($version)",
|
||||||
|
changelog_body: $changelog,
|
||||||
artifacts: [ $files | split("\n") | .[] | {
|
artifacts: [ $files | split("\n") | .[] | {
|
||||||
name: .,
|
name: .,
|
||||||
kind: (if (. | test("[.](deb|rpm)$")) then "installer" else "executable-zip" end),
|
kind: (if (. | test("[.](deb|rpm)$")) then "installer" else "executable-zip" end),
|
||||||
|
77
.github/workflows/release-cli.yml
vendored
77
.github/workflows/release-cli.yml
vendored
@ -16,6 +16,8 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
cli_version: ${{ steps.version.outputs.cli_version }}
|
cli_version: ${{ steps.version.outputs.cli_version }}
|
||||||
|
release_notes: ${{ fromJSON(steps.notes.outputs.notes_json || 'null') }}
|
||||||
|
announce: ${{ steps.announce.outputs.announce || '' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Extract version
|
- name: Extract version
|
||||||
@ -33,6 +35,40 @@ jobs:
|
|||||||
|
|
||||||
echo "cli_version=$version" >> $GITHUB_OUTPUT
|
echo "cli_version=$version" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Extract release notes
|
||||||
|
if: github.event.head_commit.message
|
||||||
|
id: notes
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
GITHUB_REPO: ${{ github.repository }}
|
||||||
|
release_commit: ${{ github.event.head_commit.message }}
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
set +eo pipefail
|
||||||
|
if [[ -z "$release_commit" ]]; then
|
||||||
|
echo "notes_json=null" >> $GITHUB_OUTPUT
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
release_pr=$(head -n1 <<< "$release_commit" | grep -oP '(?<=[(]#)\d+(?=[)])')
|
||||||
|
if [[ -z "$release_pr" ]]; then
|
||||||
|
echo "notes_json=null" >> $GITHUB_OUTPUT
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
gh \
|
||||||
|
pr --repo "$GITHUB_REPO" \
|
||||||
|
view "$release_pr" \
|
||||||
|
--json body \
|
||||||
|
--jq '"notes_json=\((.body | split("### Release notes")[1] // "") | tojson)"' \
|
||||||
|
>> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Make a new announcement post
|
||||||
|
id: announce
|
||||||
|
if: endsWith(steps.version.outputs.cli_version, '.0')
|
||||||
|
run: echo "announce=Announcements" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@ -104,10 +140,10 @@ jobs:
|
|||||||
experimental: false
|
experimental: false
|
||||||
|
|
||||||
- name: mac-arm64
|
- name: mac-arm64
|
||||||
os: macos-latest
|
os: macos-11.0
|
||||||
target: aarch64-apple-darwin
|
target: aarch64-apple-darwin
|
||||||
cross: true
|
cross: true
|
||||||
experimental: false
|
experimental: true
|
||||||
|
|
||||||
- name: windows-x86-64
|
- name: windows-x86-64
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
@ -196,29 +232,19 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
tool: cross
|
tool: cross
|
||||||
|
|
||||||
- name: Build
|
- name: Build (cargo)
|
||||||
shell: bash
|
if: "!matrix.cross"
|
||||||
run: |
|
run: cargo build --package watchexec-cli --release --locked --target ${{ matrix.target }}
|
||||||
${{ matrix.cross && 'cross' || 'cargo' }} build \
|
|
||||||
-p watchexec-cli \
|
- name: Build (cross)
|
||||||
--release --locked \
|
if: matrix.cross
|
||||||
--target ${{ matrix.target }}
|
run: cross build --package watchexec-cli --release --locked --target ${{ matrix.target }}
|
||||||
|
|
||||||
- name: Make manpage
|
- name: Make manpage
|
||||||
shell: bash
|
run: cargo run -p watchexec-cli -- --manual > doc/watchexec.1
|
||||||
run: |
|
|
||||||
cargo run -p watchexec-cli \
|
|
||||||
${{ (!matrix.cross) && '--release --target' || '' }} \
|
|
||||||
${{ (!matrix.cross) && matrix.target || '' }} \
|
|
||||||
--locked -- --manual > doc/watchexec.1
|
|
||||||
|
|
||||||
- name: Make completions
|
- name: Make completions
|
||||||
shell: bash
|
run: bin/completions
|
||||||
run: |
|
|
||||||
bin/completions \
|
|
||||||
${{ (!matrix.cross) && '--release --target' || '' }} \
|
|
||||||
${{ (!matrix.cross) && matrix.target || '' }} \
|
|
||||||
--locked
|
|
||||||
|
|
||||||
- name: Package
|
- name: Package
|
||||||
shell: bash
|
shell: bash
|
||||||
@ -258,7 +284,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.name }}
|
name: builds
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
path: |
|
path: |
|
||||||
watchexec-*.tar.xz
|
watchexec-*.tar.xz
|
||||||
@ -283,12 +309,13 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/download-artifact@v4
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
merge-multiple: true
|
name: builds
|
||||||
|
|
||||||
- name: Dist manifest
|
- name: Dist manifest
|
||||||
run: |
|
run: |
|
||||||
jq -ncf .github/workflows/dist-manifest.jq \
|
jq -ncf .github/workflows/dist-manifest.jq \
|
||||||
--arg version "${{ needs.info.outputs.cli_version }}" \
|
--arg version "${{ needs.info.outputs.cli_version }}" \
|
||||||
|
--arg changelog "${{ needs.info.outputs.release_notes }}" \
|
||||||
--arg files "$(ls watchexec-*)" \
|
--arg files "$(ls watchexec-*)" \
|
||||||
> dist-manifest.json
|
> dist-manifest.json
|
||||||
|
|
||||||
@ -306,11 +333,13 @@ jobs:
|
|||||||
sha512sum $file | cut -d ' ' -f1 > "$file.sha512"
|
sha512sum $file | cut -d ' ' -f1 > "$file.sha512"
|
||||||
done
|
done
|
||||||
|
|
||||||
- uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564
|
- uses: softprops/action-gh-release@3198ee18f814cdf787321b4a32a26ddbf37acc52
|
||||||
with:
|
with:
|
||||||
tag_name: v${{ needs.info.outputs.cli_version }}
|
tag_name: v${{ needs.info.outputs.cli_version }}
|
||||||
name: CLI v${{ needs.info.outputs.cli_version }}
|
name: CLI v${{ needs.info.outputs.cli_version }}
|
||||||
|
body: ${{ needs.info.outputs.release_notes }}
|
||||||
append_body: true
|
append_body: true
|
||||||
|
discussion_category_name: ${{ needs.info.outputs.announce }}
|
||||||
files: |
|
files: |
|
||||||
dist-manifest.json
|
dist-manifest.json
|
||||||
watchexec-*.tar.xz
|
watchexec-*.tar.xz
|
||||||
|
@ -3,8 +3,8 @@ message: |
|
|||||||
If you use this software, please cite it using these metadata.
|
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"
|
title: "Watchexec: a tool to react to filesystem changes, and a crate ecosystem to power it"
|
||||||
|
|
||||||
version: "2.1.2"
|
version: "1.25.1"
|
||||||
date-released: 2024-06-30
|
date-released: 2024-01-05
|
||||||
|
|
||||||
repository-code: https://github.com/watchexec/watchexec
|
repository-code: https://github.com/watchexec/watchexec
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
|
66
Cargo.lock
generated
66
Cargo.lock
generated
@ -488,7 +488,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bosion"
|
name = "bosion"
|
||||||
version = "1.1.0"
|
version = "1.0.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gix",
|
"gix",
|
||||||
"time",
|
"time",
|
||||||
@ -1317,7 +1317,6 @@ dependencies = [
|
|||||||
"gix-glob",
|
"gix-glob",
|
||||||
"gix-hash",
|
"gix-hash",
|
||||||
"gix-hashtable",
|
"gix-hashtable",
|
||||||
"gix-index",
|
|
||||||
"gix-lock",
|
"gix-lock",
|
||||||
"gix-macros",
|
"gix-macros",
|
||||||
"gix-object",
|
"gix-object",
|
||||||
@ -1355,15 +1354,6 @@ dependencies = [
|
|||||||
"winnow 0.6.6",
|
"winnow 0.6.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gix-bitmap"
|
|
||||||
version = "0.2.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a371db66cbd4e13f0ed9dc4c0fea712d7276805fccc877f77e96374d317e87ae"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gix-chunk"
|
name = "gix-chunk"
|
||||||
version = "0.4.8"
|
version = "0.4.8"
|
||||||
@ -1523,33 +1513,6 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gix-index"
|
|
||||||
version = "0.32.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "881ab3b1fa57f497601a5add8289e72a7ae09471fc0b9bbe483b628ae8e418a1"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.5.0",
|
|
||||||
"bstr",
|
|
||||||
"filetime",
|
|
||||||
"fnv",
|
|
||||||
"gix-bitmap",
|
|
||||||
"gix-features",
|
|
||||||
"gix-fs",
|
|
||||||
"gix-hash",
|
|
||||||
"gix-lock",
|
|
||||||
"gix-object",
|
|
||||||
"gix-traverse",
|
|
||||||
"gix-utils",
|
|
||||||
"hashbrown 0.14.3",
|
|
||||||
"itoa",
|
|
||||||
"libc",
|
|
||||||
"memmap2",
|
|
||||||
"rustix",
|
|
||||||
"smallvec",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gix-lock"
|
name = "gix-lock"
|
||||||
version = "13.1.1"
|
version = "13.1.1"
|
||||||
@ -2025,7 +1988,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ignore-files"
|
name = "ignore-files"
|
||||||
version = "3.0.1"
|
version = "3.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
"futures",
|
"futures",
|
||||||
@ -2870,7 +2833,7 @@ checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "project-origins"
|
name = "project-origins"
|
||||||
version = "1.4.0"
|
version = "1.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"miette",
|
"miette",
|
||||||
@ -3722,18 +3685,6 @@ dependencies = [
|
|||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-appender"
|
|
||||||
version = "0.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-channel",
|
|
||||||
"thiserror",
|
|
||||||
"time",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-attributes"
|
name = "tracing-attributes"
|
||||||
version = "0.1.27"
|
version = "0.1.27"
|
||||||
@ -4044,7 +3995,7 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "watchexec"
|
name = "watchexec"
|
||||||
version = "4.1.0"
|
version = "4.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-priority-channel",
|
"async-priority-channel",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
@ -4069,7 +4020,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "watchexec-cli"
|
name = "watchexec-cli"
|
||||||
version = "2.1.2"
|
version = "1.25.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"argfile",
|
"argfile",
|
||||||
@ -4085,7 +4036,6 @@ dependencies = [
|
|||||||
"console-subscriber",
|
"console-subscriber",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"dirs 5.0.1",
|
"dirs 5.0.1",
|
||||||
"dunce",
|
|
||||||
"embed-resource",
|
"embed-resource",
|
||||||
"eyra",
|
"eyra",
|
||||||
"futures",
|
"futures",
|
||||||
@ -4110,7 +4060,6 @@ dependencies = [
|
|||||||
"termcolor",
|
"termcolor",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-appender",
|
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"tracing-test",
|
"tracing-test",
|
||||||
"uuid",
|
"uuid",
|
||||||
@ -4135,11 +4084,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "watchexec-filterer-globset"
|
name = "watchexec-filterer-globset"
|
||||||
version = "4.0.1"
|
version = "3.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ignore",
|
"ignore",
|
||||||
"ignore-files",
|
"ignore-files",
|
||||||
"tempfile",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
@ -4150,7 +4098,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "watchexec-filterer-ignore"
|
name = "watchexec-filterer-ignore"
|
||||||
version = "4.0.1"
|
version = "3.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
"ignore",
|
"ignore",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
cargo run -p watchexec-cli $* -- --completions bash > completions/bash
|
cargo run -p watchexec-cli -- --completions bash > completions/bash
|
||||||
cargo run -p watchexec-cli $* -- --completions elvish > completions/elvish
|
cargo run -p watchexec-cli -- --completions elvish > completions/elvish
|
||||||
cargo run -p watchexec-cli $* -- --completions fish > completions/fish
|
cargo run -p watchexec-cli -- --completions fish > completions/fish
|
||||||
cargo run -p watchexec-cli $* -- --completions nu > completions/nu
|
cargo run -p watchexec-cli -- --completions nu > completions/nu
|
||||||
cargo run -p watchexec-cli $* -- --completions powershell > completions/powershell
|
cargo run -p watchexec-cli -- --completions powershell > completions/powershell
|
||||||
cargo run -p watchexec-cli $* -- --completions zsh > completions/zsh
|
cargo run -p watchexec-cli -- --completions zsh > completions/zsh
|
||||||
|
@ -19,7 +19,7 @@ _watchexec() {
|
|||||||
|
|
||||||
case "${cmd}" in
|
case "${cmd}" in
|
||||||
watchexec)
|
watchexec)
|
||||||
opts="-w -W -F -c -o -r -s -d -p -n -E -1 -N -q -e -f -j -i -v -h -V --watch --watch-non-recursive --watch-file --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]..."
|
opts="-w -c -o -r -s -d -p -n -E -1 -N -q -e -f -j -i -v -h -V --watch --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 --verbose --log-file --manual --completions --help --version [COMMAND]..."
|
||||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||||
return 0
|
return 0
|
||||||
@ -33,22 +33,6 @@ _watchexec() {
|
|||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
--watch-non-recursive)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-W)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--watch-file)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
-F)
|
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--clear)
|
--clear)
|
||||||
COMPREPLY=($(compgen -W "clear reset" -- "${cur}"))
|
COMPREPLY=($(compgen -W "clear reset" -- "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
@ -205,14 +189,14 @@ _watchexec() {
|
|||||||
COMPREPLY=($(compgen -W "access create remove rename modify metadata" -- "${cur}"))
|
COMPREPLY=($(compgen -W "access create remove rename modify metadata" -- "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
--completions)
|
|
||||||
COMPREPLY=($(compgen -W "bash elvish fish nu powershell zsh" -- "${cur}"))
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
--log-file)
|
--log-file)
|
||||||
COMPREPLY=($(compgen -f "${cur}"))
|
COMPREPLY=($(compgen -f "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
--completions)
|
||||||
|
COMPREPLY=($(compgen -W "bash elvish fish nu powershell zsh" -- "${cur}"))
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
;;
|
;;
|
||||||
|
@ -20,10 +20,6 @@ set edit:completion:arg-completer[watchexec] = {|@words|
|
|||||||
&'watchexec'= {
|
&'watchexec'= {
|
||||||
cand -w 'Watch a specific file or directory'
|
cand -w 'Watch a specific file or directory'
|
||||||
cand --watch '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 -F 'Watch files and directories from a file'
|
|
||||||
cand --watch-file 'Watch files and directories from a file'
|
|
||||||
cand -c 'Clear screen before running command'
|
cand -c 'Clear screen before running command'
|
||||||
cand --clear '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 -o 'What to do when receiving events while the command is running'
|
||||||
@ -56,8 +52,8 @@ set edit:completion:arg-completer[watchexec] = {|@words|
|
|||||||
cand --ignore 'Filename patterns to filter out'
|
cand --ignore 'Filename patterns to filter out'
|
||||||
cand --ignore-file 'Files to load ignores from'
|
cand --ignore-file 'Files to load ignores from'
|
||||||
cand --fs-events 'Filesystem events to filter to'
|
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 --log-file 'Write diagnostic logs to a file'
|
||||||
|
cand --completions 'Generate a shell completions script'
|
||||||
cand -r 'Restart the process if it''s still running'
|
cand -r 'Restart the process if it''s still running'
|
||||||
cand --restart '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 --stdin-quit 'Exit when stdin closes'
|
||||||
@ -82,9 +78,9 @@ set edit:completion:arg-completer[watchexec] = {|@words|
|
|||||||
cand --bell 'Ring the terminal bell on command completion'
|
cand --bell 'Ring the terminal bell on command completion'
|
||||||
cand --no-meta 'Don''t emit fs events for metadata changes'
|
cand --no-meta 'Don''t emit fs events for metadata changes'
|
||||||
cand --print-events 'Print events that trigger actions'
|
cand --print-events 'Print events that trigger actions'
|
||||||
cand --manual 'Show the manual page'
|
|
||||||
cand -v 'Set diagnostic log level'
|
cand -v 'Set diagnostic log level'
|
||||||
cand --verbose 'Set diagnostic log level'
|
cand --verbose 'Set diagnostic log level'
|
||||||
|
cand --manual 'Show the manual page'
|
||||||
cand -h 'Print help (see more with ''--help'')'
|
cand -h 'Print help (see more with ''--help'')'
|
||||||
cand --help 'Print help (see more with ''--help'')'
|
cand --help 'Print help (see more with ''--help'')'
|
||||||
cand -V 'Print version'
|
cand -V 'Print version'
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
complete -c watchexec -s w -l watch -d 'Watch a specific file or directory' -r -F
|
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 F -l watch-file -d 'Watch files and directories from a file' -r -F
|
|
||||||
complete -c watchexec -s c -l clear -d 'Clear screen before running command' -r -f -a "{clear '',reset ''}"
|
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 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 -s s -l signal -d 'Send a signal to the process when it\'s still running' -r
|
||||||
@ -24,8 +22,8 @@ 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 -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 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 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 -l log-file -d 'Write diagnostic logs to a file' -r -F
|
||||||
|
complete -c watchexec -l completions -d 'Generate a shell completions script' -r -f -a "{bash '',elvish '',fish '',nu '',powershell '',zsh ''}"
|
||||||
complete -c watchexec -s r -l restart -d 'Restart the process if it\'s still running'
|
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 stdin-quit -d 'Exit when stdin closes'
|
||||||
complete -c watchexec -l no-vcs-ignore -d 'Don\'t load gitignores'
|
complete -c watchexec -l no-vcs-ignore -d 'Don\'t load gitignores'
|
||||||
@ -46,7 +44,7 @@ complete -c watchexec -s q -l quiet -d 'Don\'t print starting and stopping messa
|
|||||||
complete -c watchexec -l bell -d 'Ring the terminal bell on command completion'
|
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 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 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 v -l verbose -d 'Set diagnostic log level'
|
||||||
|
complete -c watchexec -l manual -d 'Show the manual page'
|
||||||
complete -c watchexec -s h -l help -d 'Print help (see more with \'--help\')'
|
complete -c watchexec -s h -l help -d 'Print help (see more with \'--help\')'
|
||||||
complete -c watchexec -s V -l version -d 'Print version'
|
complete -c watchexec -s V -l version -d 'Print version'
|
||||||
|
@ -32,8 +32,6 @@ module completions {
|
|||||||
export extern watchexec [
|
export extern watchexec [
|
||||||
...command: string # Command to run on changes
|
...command: string # Command to run on changes
|
||||||
--watch(-w): string # Watch a specific file or directory
|
--watch(-w): string # Watch a specific file or directory
|
||||||
--watch-non-recursive(-W): string # Watch a specific directory, non-recursively
|
|
||||||
--watch-file(-F): string # Watch files and directories from a file
|
|
||||||
--clear(-c): string@"nu-complete watchexec screen_clear" # Clear screen before running command
|
--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
|
--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
|
--restart(-r) # Restart the process if it's still running
|
||||||
@ -77,10 +75,10 @@ module completions {
|
|||||||
--fs-events: string@"nu-complete watchexec filter_fs_events" # Filesystem events to filter to
|
--fs-events: string@"nu-complete watchexec filter_fs_events" # Filesystem events to filter to
|
||||||
--no-meta # Don't emit fs events for metadata changes
|
--no-meta # Don't emit fs events for metadata changes
|
||||||
--print-events # Print events that trigger actions
|
--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
|
--verbose(-v) # Set diagnostic log level
|
||||||
--log-file: string # Write diagnostic logs to a file
|
--log-file: string # Write diagnostic logs to a file
|
||||||
|
--manual # Show the manual page
|
||||||
|
--completions: string@"nu-complete watchexec completions" # Generate a shell completions script
|
||||||
--help(-h) # Print help (see more with '--help')
|
--help(-h) # Print help (see more with '--help')
|
||||||
--version(-V) # Print version
|
--version(-V) # Print version
|
||||||
]
|
]
|
||||||
|
@ -23,10 +23,6 @@ Register-ArgumentCompleter -Native -CommandName 'watchexec' -ScriptBlock {
|
|||||||
'watchexec' {
|
'watchexec' {
|
||||||
[CompletionResult]::new('-w', 'w', [CompletionResultType]::ParameterName, 'Watch a specific file or directory')
|
[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('--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('-F', 'F ', [CompletionResultType]::ParameterName, 'Watch files and directories from a file')
|
|
||||||
[CompletionResult]::new('--watch-file', 'watch-file', [CompletionResultType]::ParameterName, 'Watch files and directories from a file')
|
|
||||||
[CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Clear screen before running command')
|
[CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Clear screen before running command')
|
||||||
[CompletionResult]::new('--clear', 'clear', [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('-o', 'o', [CompletionResultType]::ParameterName, 'What to do when receiving events while the command is running')
|
||||||
@ -59,8 +55,8 @@ Register-ArgumentCompleter -Native -CommandName 'watchexec' -ScriptBlock {
|
|||||||
[CompletionResult]::new('--ignore', 'ignore', [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('--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('--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('--log-file', 'log-file', [CompletionResultType]::ParameterName, 'Write diagnostic logs to a file')
|
||||||
|
[CompletionResult]::new('--completions', 'completions', [CompletionResultType]::ParameterName, 'Generate a shell completions script')
|
||||||
[CompletionResult]::new('-r', 'r', [CompletionResultType]::ParameterName, 'Restart the process if it''s still running')
|
[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('--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('--stdin-quit', 'stdin-quit', [CompletionResultType]::ParameterName, 'Exit when stdin closes')
|
||||||
@ -85,9 +81,9 @@ Register-ArgumentCompleter -Native -CommandName 'watchexec' -ScriptBlock {
|
|||||||
[CompletionResult]::new('--bell', 'bell', [CompletionResultType]::ParameterName, 'Ring the terminal bell on command completion')
|
[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('--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('--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('-v', 'v', [CompletionResultType]::ParameterName, 'Set diagnostic log level')
|
||||||
[CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'Set diagnostic log level')
|
[CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'Set diagnostic log level')
|
||||||
|
[CompletionResult]::new('--manual', 'manual', [CompletionResultType]::ParameterName, 'Show the manual page')
|
||||||
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
|
[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('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')')
|
||||||
[CompletionResult]::new('-V', 'V ', [CompletionResultType]::ParameterName, 'Print version')
|
[CompletionResult]::new('-V', 'V ', [CompletionResultType]::ParameterName, 'Print version')
|
||||||
|
@ -17,10 +17,6 @@ _watchexec() {
|
|||||||
_arguments "${_arguments_options[@]}" \
|
_arguments "${_arguments_options[@]}" \
|
||||||
'*-w+[Watch a specific file or directory]:PATH:_files' \
|
'*-w+[Watch a specific file or directory]:PATH:_files' \
|
||||||
'*--watch=[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' \
|
|
||||||
'-F+[Watch files and directories from a file]:PATH:_files' \
|
|
||||||
'--watch-file=[Watch files and directories from a file]:PATH:_files' \
|
|
||||||
'-c+[Clear screen before running command]' \
|
'-c+[Clear screen before running command]' \
|
||||||
'--clear=[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)' \
|
'-o+[What to do when receiving events while the command is running]:MODE:(queue do-nothing restart signal)' \
|
||||||
@ -53,8 +49,8 @@ _watchexec() {
|
|||||||
'*--ignore=[Filename patterns to filter out]:PATTERN: ' \
|
'*--ignore=[Filename patterns to filter out]:PATTERN: ' \
|
||||||
'*--ignore-file=[Files to load ignores from]:PATH:_files' \
|
'*--ignore-file=[Files to load ignores from]:PATH:_files' \
|
||||||
'*--fs-events=[Filesystem events to filter to]:EVENTS:(access create remove rename modify metadata)' \
|
'*--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]' \
|
'--log-file=[Write diagnostic logs to a file]' \
|
||||||
|
'(--manual)--completions=[Generate a shell completions script]:COMPLETIONS:(bash elvish fish nu powershell zsh)' \
|
||||||
'(-o --on-busy-update)-r[Restart the process if it'\''s still running]' \
|
'(-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]' \
|
'(-o --on-busy-update)--restart[Restart the process if it'\''s still running]' \
|
||||||
'--stdin-quit[Exit when stdin closes]' \
|
'--stdin-quit[Exit when stdin closes]' \
|
||||||
@ -79,9 +75,9 @@ _watchexec() {
|
|||||||
'--bell[Ring the terminal bell on command completion]' \
|
'--bell[Ring the terminal bell on command completion]' \
|
||||||
'(--fs-events)--no-meta[Don'\''t emit fs events for metadata changes]' \
|
'(--fs-events)--no-meta[Don'\''t emit fs events for metadata changes]' \
|
||||||
'--print-events[Print events that trigger actions]' \
|
'--print-events[Print events that trigger actions]' \
|
||||||
'(--completions)--manual[Show the manual page]' \
|
|
||||||
'*-v[Set diagnostic log level]' \
|
'*-v[Set diagnostic log level]' \
|
||||||
'*--verbose[Set diagnostic log level]' \
|
'*--verbose[Set diagnostic log level]' \
|
||||||
|
'(--completions)--manual[Show the manual page]' \
|
||||||
'-h[Print help (see more with '\''--help'\'')]' \
|
'-h[Print help (see more with '\''--help'\'')]' \
|
||||||
'--help[Print help (see more with '\''--help'\'')]' \
|
'--help[Print help (see more with '\''--help'\'')]' \
|
||||||
'-V[Print version]' \
|
'-V[Print version]' \
|
||||||
|
@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
## Next (YYYY-MM-DD)
|
## Next (YYYY-MM-DD)
|
||||||
|
|
||||||
## v1.1.0 (2024-05-16)
|
|
||||||
|
|
||||||
- Add `git-describe` support (#832, by @lu-zero)
|
|
||||||
|
|
||||||
## v1.0.3 (2024-04-20)
|
## v1.0.3 (2024-04-20)
|
||||||
|
|
||||||
- Deps: gix 0.62
|
- Deps: gix 0.62
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bosion"
|
name = "bosion"
|
||||||
version = "1.1.0"
|
version = "1.0.3"
|
||||||
|
|
||||||
authors = ["Félix Saparelli <felix@passcod.name>"]
|
authors = ["Félix Saparelli <felix@passcod.name>"]
|
||||||
license = "Apache-2.0 OR MIT"
|
license = "Apache-2.0 OR MIT"
|
||||||
@ -22,7 +22,6 @@ features = ["macros", "formatting"]
|
|||||||
version = "0.62.0"
|
version = "0.62.0"
|
||||||
optional = true
|
optional = true
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["revision"]
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["git", "reproducible", "std"]
|
default = ["git", "reproducible", "std"]
|
||||||
|
@ -15,7 +15,7 @@ In your `Cargo.toml`:
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bosion = "1.1.0"
|
bosion = "1.0.3"
|
||||||
```
|
```
|
||||||
|
|
||||||
In your `build.rs`:
|
In your `build.rs`:
|
||||||
|
105
crates/bosion/examples/clap/Cargo.lock
generated
105
crates/bosion/examples/clap/Cargo.lock
generated
@ -8,24 +8,6 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ahash"
|
|
||||||
version = "0.8.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
"version_check",
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "allocator-api2"
|
|
||||||
version = "0.2.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.13"
|
version = "0.6.13"
|
||||||
@ -100,7 +82,7 @@ checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bosion"
|
name = "bosion"
|
||||||
version = "1.0.3"
|
version = "1.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gix",
|
"gix",
|
||||||
"time",
|
"time",
|
||||||
@ -229,18 +211,6 @@ version = "2.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "filetime"
|
|
||||||
version = "0.2.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.28"
|
version = "1.0.28"
|
||||||
@ -251,12 +221,6 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fnv"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@ -283,7 +247,6 @@ dependencies = [
|
|||||||
"gix-glob",
|
"gix-glob",
|
||||||
"gix-hash",
|
"gix-hash",
|
||||||
"gix-hashtable",
|
"gix-hashtable",
|
||||||
"gix-index",
|
|
||||||
"gix-lock",
|
"gix-lock",
|
||||||
"gix-macros",
|
"gix-macros",
|
||||||
"gix-object",
|
"gix-object",
|
||||||
@ -321,15 +284,6 @@ dependencies = [
|
|||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gix-bitmap"
|
|
||||||
version = "0.2.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a371db66cbd4e13f0ed9dc4c0fea712d7276805fccc877f77e96374d317e87ae"
|
|
||||||
dependencies = [
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gix-chunk"
|
name = "gix-chunk"
|
||||||
version = "0.4.8"
|
version = "0.4.8"
|
||||||
@ -489,33 +443,6 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gix-index"
|
|
||||||
version = "0.32.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "881ab3b1fa57f497601a5add8289e72a7ae09471fc0b9bbe483b628ae8e418a1"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.5.0",
|
|
||||||
"bstr",
|
|
||||||
"filetime",
|
|
||||||
"fnv",
|
|
||||||
"gix-bitmap",
|
|
||||||
"gix-features",
|
|
||||||
"gix-fs",
|
|
||||||
"gix-hash",
|
|
||||||
"gix-lock",
|
|
||||||
"gix-object",
|
|
||||||
"gix-traverse",
|
|
||||||
"gix-utils",
|
|
||||||
"hashbrown",
|
|
||||||
"itoa",
|
|
||||||
"libc",
|
|
||||||
"memmap2",
|
|
||||||
"rustix",
|
|
||||||
"smallvec",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gix-lock"
|
name = "gix-lock"
|
||||||
version = "13.1.1"
|
version = "13.1.1"
|
||||||
@ -775,10 +702,6 @@ name = "hashbrown"
|
|||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
"allocator-api2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
@ -1153,12 +1076,6 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version_check"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@ -1338,23 +1255,3 @@ checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy"
|
|
||||||
version = "0.7.34"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy-derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "zerocopy-derive"
|
|
||||||
version = "0.7.34"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
@ -13,9 +13,6 @@ struct Args {
|
|||||||
|
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
dates: bool,
|
dates: bool,
|
||||||
|
|
||||||
#[clap(long)]
|
|
||||||
describe: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -26,15 +23,17 @@ fn main() {
|
|||||||
"{}",
|
"{}",
|
||||||
Bosion::long_version_with(&[("extra", "field"), ("custom", "1.2.3"),])
|
Bosion::long_version_with(&[("extra", "field"), ("custom", "1.2.3"),])
|
||||||
);
|
);
|
||||||
} else if args.features {
|
} else
|
||||||
|
|
||||||
|
if args.features {
|
||||||
println!("Features: {}", Bosion::CRATE_FEATURE_STRING);
|
println!("Features: {}", Bosion::CRATE_FEATURE_STRING);
|
||||||
} else if args.dates {
|
} else
|
||||||
|
|
||||||
|
if args.dates {
|
||||||
println!("commit date: {}", Bosion::GIT_COMMIT_DATE);
|
println!("commit date: {}", Bosion::GIT_COMMIT_DATE);
|
||||||
println!("commit datetime: {}", Bosion::GIT_COMMIT_DATETIME);
|
println!("commit datetime: {}", Bosion::GIT_COMMIT_DATETIME);
|
||||||
println!("build date: {}", Bosion::BUILD_DATE);
|
println!("build date: {}", Bosion::BUILD_DATE);
|
||||||
println!("build datetime: {}", Bosion::BUILD_DATETIME);
|
println!("build datetime: {}", Bosion::BUILD_DATETIME);
|
||||||
} else if args.describe {
|
|
||||||
println!("commit description: {}", Bosion::GIT_COMMIT_DESCRIPTION);
|
|
||||||
} else {
|
} else {
|
||||||
println!("{}", Bosion::LONG_VERSION);
|
println!("{}", Bosion::LONG_VERSION);
|
||||||
}
|
}
|
||||||
|
@ -145,9 +145,6 @@ pub struct GitInfo {
|
|||||||
|
|
||||||
/// The datetime of the current commit, in the format `YYYY-MM-DD HH:MM:SS`, at UTC.
|
/// The datetime of the current commit, in the format `YYYY-MM-DD HH:MM:SS`, at UTC.
|
||||||
pub git_datetime: String,
|
pub git_datetime: String,
|
||||||
|
|
||||||
/// The `git describe` equivalent output
|
|
||||||
pub git_description: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "git")]
|
#[cfg(feature = "git")]
|
||||||
@ -166,7 +163,6 @@ impl GitInfo {
|
|||||||
git_shorthash: head.short_id().err_string()?.to_string(),
|
git_shorthash: head.short_id().err_string()?.to_string(),
|
||||||
git_date: timestamp.format(DATE_FORMAT).err_string()?,
|
git_date: timestamp.format(DATE_FORMAT).err_string()?,
|
||||||
git_datetime: timestamp.format(DATETIME_FORMAT).err_string()?,
|
git_datetime: timestamp.format(DATETIME_FORMAT).err_string()?,
|
||||||
git_description: head.describe().format().err_string()?.to_string(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,6 @@ pub fn gather_to(filename: &str, structname: &str, public: bool) {
|
|||||||
git_shorthash,
|
git_shorthash,
|
||||||
git_date,
|
git_date,
|
||||||
git_datetime,
|
git_datetime,
|
||||||
git_description,
|
|
||||||
..
|
..
|
||||||
}) = git
|
}) = git
|
||||||
{
|
{
|
||||||
@ -105,11 +104,6 @@ pub fn gather_to(filename: &str, structname: &str, public: bool) {
|
|||||||
/// This is the date and time (`YYYY-MM-DD HH:MM:SS`) of the commit that was built. Same
|
/// 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.
|
/// caveats as with `GIT_COMMIT_HASH` apply.
|
||||||
pub const GIT_COMMIT_DATETIME: &'static str = {git_datetime:?};
|
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}"))
|
), 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 {
|
} else {
|
||||||
@ -250,7 +244,6 @@ pub fn gather_to_env_with_prefix(prefix: &str) {
|
|||||||
git_shorthash,
|
git_shorthash,
|
||||||
git_date,
|
git_date,
|
||||||
git_datetime,
|
git_datetime,
|
||||||
git_description,
|
|
||||||
..
|
..
|
||||||
}) = git
|
}) = git
|
||||||
{
|
{
|
||||||
@ -258,6 +251,5 @@ pub fn gather_to_env_with_prefix(prefix: &str) {
|
|||||||
println!("cargo:rustc-env={prefix}GIT_COMMIT_SHORTHASH={git_shorthash}");
|
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_DATE={git_date}");
|
||||||
println!("cargo:rustc-env={prefix}GIT_COMMIT_DATETIME={git_datetime}");
|
println!("cargo:rustc-env={prefix}GIT_COMMIT_DATETIME={git_datetime}");
|
||||||
println!("cargo:rustc-env={prefix}GIT_COMMIT_DESCRIPTION={git_description}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "watchexec-cli"
|
name = "watchexec-cli"
|
||||||
version = "2.1.2"
|
version = "1.25.1"
|
||||||
|
|
||||||
authors = ["Félix Saparelli <felix@passcod.name>", "Matt Green <mattgreenrocks@gmail.com>"]
|
authors = ["Félix Saparelli <felix@passcod.name>", "Matt Green <mattgreenrocks@gmail.com>"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
@ -29,7 +29,6 @@ clap_mangen = "0.2.15"
|
|||||||
clearscreen = "3.0.0"
|
clearscreen = "3.0.0"
|
||||||
dashmap = "5.4.0"
|
dashmap = "5.4.0"
|
||||||
dirs = "5.0.0"
|
dirs = "5.0.0"
|
||||||
dunce = "1.0.4"
|
|
||||||
futures = "0.3.29"
|
futures = "0.3.29"
|
||||||
humantime = "2.1.0"
|
humantime = "2.1.0"
|
||||||
indexmap = "2.2.6" # needs to be in sync with jaq's
|
indexmap = "2.2.6" # needs to be in sync with jaq's
|
||||||
@ -45,7 +44,6 @@ serde_json = "1.0.107"
|
|||||||
tempfile = "3.8.1"
|
tempfile = "3.8.1"
|
||||||
termcolor = "1.4.0"
|
termcolor = "1.4.0"
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-appender = "0.2.3"
|
|
||||||
which = "6.0.1"
|
which = "6.0.1"
|
||||||
|
|
||||||
[dependencies.blake3]
|
[dependencies.blake3]
|
||||||
@ -70,7 +68,7 @@ features = ["log", "env_logger"]
|
|||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.ignore-files]
|
[dependencies.ignore-files]
|
||||||
version = "3.0.1"
|
version = "3.0.0"
|
||||||
path = "../ignore-files"
|
path = "../ignore-files"
|
||||||
|
|
||||||
[dependencies.miette]
|
[dependencies.miette]
|
||||||
@ -82,11 +80,11 @@ version = "0.1.1"
|
|||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.project-origins]
|
[dependencies.project-origins]
|
||||||
version = "1.4.0"
|
version = "1.3.0"
|
||||||
path = "../project-origins"
|
path = "../project-origins"
|
||||||
|
|
||||||
[dependencies.watchexec]
|
[dependencies.watchexec]
|
||||||
version = "4.1.0"
|
version = "4.0.0"
|
||||||
path = "../lib"
|
path = "../lib"
|
||||||
|
|
||||||
[dependencies.watchexec-events]
|
[dependencies.watchexec-events]
|
||||||
@ -99,7 +97,7 @@ version = "3.0.0"
|
|||||||
path = "../signals"
|
path = "../signals"
|
||||||
|
|
||||||
[dependencies.watchexec-filterer-globset]
|
[dependencies.watchexec-filterer-globset]
|
||||||
version = "4.0.1"
|
version = "3.0.0"
|
||||||
path = "../filterer/globset"
|
path = "../filterer/globset"
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
@ -131,7 +129,7 @@ mimalloc = "0.1.39"
|
|||||||
embed-resource = "2.4.0"
|
embed-resource = "2.4.0"
|
||||||
|
|
||||||
[build-dependencies.bosion]
|
[build-dependencies.bosion]
|
||||||
version = "1.1.0"
|
version = "1.0.3"
|
||||||
path = "../bosion"
|
path = "../bosion"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
@ -172,7 +170,7 @@ assets = [
|
|||||||
["../../target/release/watchexec", "usr/bin/watchexec", "755"],
|
["../../target/release/watchexec", "usr/bin/watchexec", "755"],
|
||||||
["README.md", "usr/share/doc/watchexec/README", "644"],
|
["README.md", "usr/share/doc/watchexec/README", "644"],
|
||||||
["../../doc/watchexec.1.md", "usr/share/doc/watchexec/watchexec.1.md", "644"],
|
["../../doc/watchexec.1.md", "usr/share/doc/watchexec/watchexec.1.md", "644"],
|
||||||
["../../doc/watchexec.1", "usr/share/man/man1/watchexec.1", "644"],
|
["../../doc/watchexec.1", "usr/share/man/man1/watchexec.1.html", "644"],
|
||||||
["../../completions/bash", "usr/share/bash-completion/completions/watchexec", "644"],
|
["../../completions/bash", "usr/share/bash-completion/completions/watchexec", "644"],
|
||||||
["../../completions/fish", "usr/share/fish/vendor_completions.d/watchexec.fish", "644"],
|
["../../completions/fish", "usr/share/fish/vendor_completions.d/watchexec.fish", "644"],
|
||||||
["../../completions/zsh", "usr/share/zsh/site-functions/_watchexec", "644"],
|
["../../completions/zsh", "usr/share/zsh/site-functions/_watchexec", "644"],
|
||||||
@ -184,7 +182,7 @@ assets = [
|
|||||||
{ source = "../../target/release/watchexec", dest = "/usr/bin/watchexec", mode = "755" },
|
{ source = "../../target/release/watchexec", dest = "/usr/bin/watchexec", mode = "755" },
|
||||||
{ source = "README.md", dest = "/usr/share/doc/watchexec/README", mode = "644", doc = true },
|
{ 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.md", dest = "/usr/share/doc/watchexec/watchexec.1.md", mode = "644", doc = true },
|
||||||
{ source = "../../doc/watchexec.1", dest = "/usr/share/man/man1/watchexec.1", mode = "644" },
|
{ 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/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/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 = "../../completions/zsh", dest = "/usr/share/zsh/site-functions/_watchexec", mode = "644" },
|
||||||
|
@ -2,8 +2,6 @@ pre-release-commit-message = "release: cli v{{version}}"
|
|||||||
tag-prefix = ""
|
tag-prefix = ""
|
||||||
tag-message = "watchexec {{version}}"
|
tag-message = "watchexec {{version}}"
|
||||||
|
|
||||||
pre-release-hook = ["sh", "-c", "cd ../.. && bin/completions && bin/manpage"]
|
|
||||||
|
|
||||||
[[pre-release-replacements]]
|
[[pre-release-replacements]]
|
||||||
file = "watchexec.exe.manifest"
|
file = "watchexec.exe.manifest"
|
||||||
search = "^ version=\"[\\d.]+[.]0\""
|
search = "^ version=\"[\\d.]+[.]0\""
|
||||||
|
@ -1,32 +1,21 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::BTreeSet,
|
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
mem::take,
|
path::PathBuf,
|
||||||
path::{Path, PathBuf},
|
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use dunce::canonicalize;
|
|
||||||
|
|
||||||
use clap::{
|
use clap::{
|
||||||
builder::TypedValueParser, error::ErrorKind, Arg, Command, CommandFactory, Parser, ValueEnum,
|
builder::TypedValueParser, error::ErrorKind, Arg, ArgAction, Command, CommandFactory, Parser,
|
||||||
ValueHint,
|
ValueEnum, ValueHint,
|
||||||
};
|
};
|
||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
use tokio::{
|
use tokio::{fs::File, io::AsyncReadExt};
|
||||||
fs::File,
|
use watchexec::paths::PATH_SEPARATOR;
|
||||||
io::{AsyncBufReadExt, AsyncReadExt, BufReader},
|
|
||||||
};
|
|
||||||
use tracing::{debug, info, trace, warn};
|
|
||||||
use tracing_appender::non_blocking::WorkerGuard;
|
|
||||||
use watchexec::{paths::PATH_SEPARATOR, sources::fs::WatchedPath};
|
|
||||||
use watchexec_signals::Signal;
|
use watchexec_signals::Signal;
|
||||||
|
|
||||||
use crate::filterer::parse::parse_filter_program;
|
use crate::filterer::parse::parse_filter_program;
|
||||||
|
|
||||||
mod logging;
|
|
||||||
|
|
||||||
const OPTSET_FILTERING: &str = "Filtering";
|
const OPTSET_FILTERING: &str = "Filtering";
|
||||||
const OPTSET_COMMAND: &str = "Command";
|
const OPTSET_COMMAND: &str = "Command";
|
||||||
const OPTSET_DEBUGGING: &str = "Debugging";
|
const OPTSET_DEBUGGING: &str = "Debugging";
|
||||||
@ -139,42 +128,7 @@ pub struct Args {
|
|||||||
value_hint = ValueHint::AnyPath,
|
value_hint = ValueHint::AnyPath,
|
||||||
value_name = "PATH",
|
value_name = "PATH",
|
||||||
)]
|
)]
|
||||||
pub recursive_paths: Vec<PathBuf>,
|
pub paths: Vec<PathBuf>,
|
||||||
|
|
||||||
/// Watch a specific directory, non-recursively
|
|
||||||
///
|
|
||||||
/// Unlike '-w', folders watched with this option are not recursed into.
|
|
||||||
///
|
|
||||||
/// This option can be specified multiple times to watch multiple directories non-recursively.
|
|
||||||
#[arg(
|
|
||||||
short = 'W',
|
|
||||||
long = "watch-non-recursive",
|
|
||||||
help_heading = OPTSET_FILTERING,
|
|
||||||
value_hint = ValueHint::AnyPath,
|
|
||||||
value_name = "PATH",
|
|
||||||
)]
|
|
||||||
pub non_recursive_paths: Vec<PathBuf>,
|
|
||||||
|
|
||||||
/// Watch files and directories from a file
|
|
||||||
///
|
|
||||||
/// Each line in the file will be interpreted as if given to '-w'.
|
|
||||||
///
|
|
||||||
/// For more complex uses (like watching non-recursively), use the argfile capability: build a
|
|
||||||
/// file containing command-line options and pass it to watchexec with `@path/to/argfile`.
|
|
||||||
///
|
|
||||||
/// The special value '-' will read from STDIN; this in incompatible with '--stdin-quit'.
|
|
||||||
#[arg(
|
|
||||||
short = 'F',
|
|
||||||
long,
|
|
||||||
help_heading = OPTSET_FILTERING,
|
|
||||||
value_hint = ValueHint::AnyPath,
|
|
||||||
value_name = "PATH",
|
|
||||||
)]
|
|
||||||
pub watch_file: Option<PathBuf>,
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[arg(skip)]
|
|
||||||
pub paths: Vec<WatchedPath>,
|
|
||||||
|
|
||||||
/// Clear screen before running command
|
/// Clear screen before running command
|
||||||
///
|
///
|
||||||
@ -191,14 +145,17 @@ pub struct Args {
|
|||||||
|
|
||||||
/// What to do when receiving events while the command is running
|
/// What to do when receiving events while the command is running
|
||||||
///
|
///
|
||||||
/// Default is to 'do-nothing', which ignores events while the command is running, so that
|
/// Default is to 'queue' up events and run the command once again when the previous run has
|
||||||
/// changes that occur due to the command are ignored, like compilation outputs. You can also
|
/// finished. You can also use 'do-nothing', which ignores events while the command is running
|
||||||
/// use 'queue' which will run the command once again when the current run has finished if any
|
/// and may be useful to avoid spurious changes made by that command, or 'restart', which
|
||||||
/// events occur while it's running, or 'restart', which terminates the running command and starts
|
/// terminates the running command and starts a new one. Finally, there's 'signal', which only
|
||||||
/// a new one. Finally, there's 'signal', which only sends a signal; this can be useful with
|
/// sends a signal; this can be useful with programs that can reload their configuration without
|
||||||
/// programs that can reload their configuration without a full restart.
|
/// a full restart.
|
||||||
///
|
///
|
||||||
/// The signal can be specified with the '--signal' option.
|
/// The signal can be specified with the '--signal' option.
|
||||||
|
///
|
||||||
|
/// Note that this option is scheduled to change its default to 'do-nothing' in the next major
|
||||||
|
/// release. File an issue if you have any concerns.
|
||||||
#[arg(
|
#[arg(
|
||||||
short,
|
short,
|
||||||
long,
|
long,
|
||||||
@ -837,7 +794,6 @@ pub struct Args {
|
|||||||
///
|
///
|
||||||
/// Provide your own custom filter programs in jaq (similar to jq) syntax. Programs are given
|
/// Provide your own custom filter programs in jaq (similar to jq) syntax. Programs are given
|
||||||
/// an event in the same format as described in '--emit-events-to' and must return a boolean.
|
/// an event in the same format as described in '--emit-events-to' and must return a boolean.
|
||||||
/// Invalid programs will make watchexec fail to start; use '-v' to see program runtime errors.
|
|
||||||
///
|
///
|
||||||
/// In addition to the jaq stdlib, watchexec adds some custom filter definitions:
|
/// In addition to the jaq stdlib, watchexec adds some custom filter definitions:
|
||||||
///
|
///
|
||||||
@ -968,13 +924,54 @@ pub struct Args {
|
|||||||
/// This prints the events that triggered the action when handling it (after debouncing), in a
|
/// This prints the events that triggered the action when handling it (after debouncing), in a
|
||||||
/// human readable form. This is useful for debugging filters.
|
/// human readable form. This is useful for debugging filters.
|
||||||
///
|
///
|
||||||
/// Use '-vvv' instead when you need more diagnostic information.
|
/// Use '-v' when you need more diagnostic information.
|
||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
help_heading = OPTSET_DEBUGGING,
|
help_heading = OPTSET_DEBUGGING,
|
||||||
)]
|
)]
|
||||||
pub print_events: bool,
|
pub print_events: bool,
|
||||||
|
|
||||||
|
/// 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 = OPTSET_DEBUGGING,
|
||||||
|
action = ArgAction::Count,
|
||||||
|
num_args = 0,
|
||||||
|
)]
|
||||||
|
pub verbose: Option<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 = OPTSET_DEBUGGING,
|
||||||
|
num_args = 0..=1,
|
||||||
|
default_missing_value = ".",
|
||||||
|
value_hint = ValueHint::AnyPath,
|
||||||
|
value_name = "PATH",
|
||||||
|
)]
|
||||||
|
pub log_file: Option<PathBuf>,
|
||||||
|
|
||||||
/// Show the manual page
|
/// Show the manual page
|
||||||
///
|
///
|
||||||
/// This shows the manual page for Watchexec, if the output is a terminal and the 'man' program
|
/// This shows the manual page for Watchexec, if the output is a terminal and the 'man' program
|
||||||
@ -999,9 +996,6 @@ pub struct Args {
|
|||||||
conflicts_with_all = ["command", "manual"],
|
conflicts_with_all = ["command", "manual"],
|
||||||
)]
|
)]
|
||||||
pub completions: Option<ShellCompletion>,
|
pub completions: Option<ShellCompletion>,
|
||||||
|
|
||||||
#[command(flatten)]
|
|
||||||
pub logging: logging::LoggingArgs,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, ValueEnum)]
|
#[derive(Clone, Copy, Debug, Default, ValueEnum)]
|
||||||
@ -1168,10 +1162,11 @@ fn expand_args_up_to_doubledash() -> Result<Vec<OsString>, std::io::Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn get_args() -> Result<(Args, Option<WorkerGuard>)> {
|
pub async fn get_args() -> Result<Args> {
|
||||||
let prearg_logs = logging::preargs();
|
use tracing::{debug, trace, warn};
|
||||||
if prearg_logs {
|
|
||||||
warn!("⚠ RUST_LOG environment variable set or hardcoded, logging options have no effect");
|
if std::env::var("RUST_LOG").is_ok() {
|
||||||
|
warn!("⚠ RUST_LOG environment variable set, logging options have no effect");
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("expanding @argfile arguments if any");
|
debug!("expanding @argfile arguments if any");
|
||||||
@ -1180,12 +1175,6 @@ pub async fn get_args() -> Result<(Args, Option<WorkerGuard>)> {
|
|||||||
debug!("parsing arguments");
|
debug!("parsing arguments");
|
||||||
let mut args = Args::parse_from(args);
|
let mut args = Args::parse_from(args);
|
||||||
|
|
||||||
let log_guard = if !prearg_logs {
|
|
||||||
logging::postargs(&args.logging).await?
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// https://no-color.org/
|
// https://no-color.org/
|
||||||
if args.color == ColourMode::Auto && std::env::var("NO_COLOR").is_ok() {
|
if args.color == ColourMode::Auto && std::env::var("NO_COLOR").is_ok() {
|
||||||
args.color = ColourMode::Never;
|
args.color = ColourMode::Never;
|
||||||
@ -1206,12 +1195,10 @@ pub async fn get_args() -> Result<(Args, Option<WorkerGuard>)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if args.no_environment {
|
if args.no_environment {
|
||||||
warn!("--no-environment is deprecated");
|
|
||||||
args.emit_events_to = EmitEvents::None;
|
args.emit_events_to = EmitEvents::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.no_process_group {
|
if args.no_process_group {
|
||||||
warn!("--no-process-group is deprecated");
|
|
||||||
args.wrap_process = WrapMode::None;
|
args.wrap_process = WrapMode::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1237,88 +1224,6 @@ pub async fn get_args() -> Result<(Args, Option<WorkerGuard>)> {
|
|||||||
.exit();
|
.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.stdin_quit && args.watch_file == Some(PathBuf::from("-")) {
|
|
||||||
Args::command()
|
|
||||||
.error(
|
|
||||||
ErrorKind::InvalidValue,
|
|
||||||
"stdin-quit cannot be used when --watch-file=-",
|
|
||||||
)
|
|
||||||
.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
let workdir = if let Some(w) = take(&mut args.workdir) {
|
|
||||||
w
|
|
||||||
} else {
|
|
||||||
let curdir = std::env::current_dir().into_diagnostic()?;
|
|
||||||
canonicalize(curdir).into_diagnostic()?
|
|
||||||
};
|
|
||||||
info!(path=?workdir, "effective working directory");
|
|
||||||
args.workdir = Some(workdir.clone());
|
|
||||||
|
|
||||||
let project_origin = if let Some(p) = take(&mut args.project_origin) {
|
|
||||||
p
|
|
||||||
} else {
|
|
||||||
crate::dirs::project_origin(&args).await?
|
|
||||||
};
|
|
||||||
info!(path=?project_origin, "effective project origin");
|
|
||||||
args.project_origin = Some(project_origin.clone());
|
|
||||||
|
|
||||||
if let Some(watch_file) = args.watch_file.as_ref() {
|
|
||||||
if watch_file == Path::new("-") {
|
|
||||||
let file = tokio::io::stdin();
|
|
||||||
let mut lines = BufReader::new(file).lines();
|
|
||||||
while let Ok(Some(line)) = lines.next_line().await {
|
|
||||||
args.recursive_paths.push(line.into());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let file = File::open(watch_file).await.into_diagnostic()?;
|
|
||||||
let mut lines = BufReader::new(file).lines();
|
|
||||||
while let Ok(Some(line)) = lines.next_line().await {
|
|
||||||
args.recursive_paths.push(line.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
args.paths = take(&mut args.recursive_paths)
|
|
||||||
.into_iter()
|
|
||||||
.map(|path| {
|
|
||||||
{
|
|
||||||
if path.is_absolute() {
|
|
||||||
Ok(path)
|
|
||||||
} else {
|
|
||||||
canonicalize(project_origin.join(path)).into_diagnostic()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.map(WatchedPath::recursive)
|
|
||||||
})
|
|
||||||
.chain(take(&mut args.non_recursive_paths).into_iter().map(|path| {
|
|
||||||
{
|
|
||||||
if path.is_absolute() {
|
|
||||||
Ok(path)
|
|
||||||
} else {
|
|
||||||
canonicalize(project_origin.join(path)).into_diagnostic()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.map(WatchedPath::non_recursive)
|
|
||||||
}))
|
|
||||||
.collect::<Result<BTreeSet<_>>>()?
|
|
||||||
.into_iter()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if args.paths.len() == 1
|
|
||||||
&& args
|
|
||||||
.paths
|
|
||||||
.first()
|
|
||||||
.map_or(false, |p| p.as_ref() == Path::new("/dev/null"))
|
|
||||||
{
|
|
||||||
info!("only path is /dev/null, not watching anything");
|
|
||||||
args.paths = Vec::new();
|
|
||||||
} else if args.paths.is_empty() {
|
|
||||||
info!("no paths, using current directory");
|
|
||||||
args.paths.push(args.workdir.clone().unwrap().into());
|
|
||||||
}
|
|
||||||
info!(paths=?args.paths, "effective watched paths");
|
|
||||||
|
|
||||||
for (n, prog) in args.filter_programs.iter_mut().enumerate() {
|
for (n, prog) in args.filter_programs.iter_mut().enumerate() {
|
||||||
if let Some(progpath) = prog.strip_prefix('@') {
|
if let Some(progpath) = prog.strip_prefix('@') {
|
||||||
trace!(?n, path=?progpath, "reading filter program from file");
|
trace!(?n, path=?progpath, "reading filter program from file");
|
||||||
@ -1331,14 +1236,12 @@ pub async fn get_args() -> Result<(Args, Option<WorkerGuard>)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args.filter_programs_parsed = take(&mut args.filter_programs)
|
args.filter_programs_parsed = std::mem::take(&mut args.filter_programs)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(parse_filter_program)
|
.map(parse_filter_program)
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
debug_assert!(args.workdir.is_some());
|
debug!(?args, "got arguments");
|
||||||
debug_assert!(args.project_origin.is_some());
|
Ok(args)
|
||||||
info!(?args, "got arguments");
|
|
||||||
Ok((args, log_guard))
|
|
||||||
}
|
}
|
||||||
|
@ -1,132 +0,0 @@
|
|||||||
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))
|
|
||||||
}
|
|
@ -1,10 +1,11 @@
|
|||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
env::var,
|
env::{current_dir, var},
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{IsTerminal, Write},
|
io::{IsTerminal, Write},
|
||||||
|
path::Path,
|
||||||
process::Stdio,
|
process::Stdio,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, AtomicU8, Ordering},
|
atomic::{AtomicBool, AtomicU8, Ordering},
|
||||||
@ -67,7 +68,19 @@ pub fn make_config(args: &Args, state: &State) -> Result<Config> {
|
|||||||
eprintln!("[[Error (not fatal)]]\n{}", Report::new(err.error));
|
eprintln!("[[Error (not fatal)]]\n{}", Report::new(err.error));
|
||||||
});
|
});
|
||||||
|
|
||||||
config.pathset(args.paths.clone());
|
config.pathset(if args.paths.is_empty() {
|
||||||
|
vec![current_dir().into_diagnostic()?]
|
||||||
|
} else if args.paths.len() == 1
|
||||||
|
&& args
|
||||||
|
.paths
|
||||||
|
.first()
|
||||||
|
.map_or(false, |p| p == Path::new("/dev/null"))
|
||||||
|
{
|
||||||
|
// special case: /dev/null means "don't start the fs event source"
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
args.paths.clone()
|
||||||
|
});
|
||||||
|
|
||||||
config.throttle(args.debounce.0);
|
config.throttle(args.debounce.0);
|
||||||
config.keyboard_events(args.stdin_quit);
|
config.keyboard_events(args.stdin_quit);
|
||||||
|
@ -16,6 +16,7 @@ use watchexec_filterer_globset::GlobsetFilterer;
|
|||||||
|
|
||||||
use crate::args::{Args, FsEvent};
|
use crate::args::{Args, FsEvent};
|
||||||
|
|
||||||
|
mod dirs;
|
||||||
pub(crate) mod parse;
|
pub(crate) mod parse;
|
||||||
mod proglib;
|
mod proglib;
|
||||||
mod progs;
|
mod progs;
|
||||||
@ -70,14 +71,13 @@ impl Filterer for WatchexecFilterer {
|
|||||||
impl WatchexecFilterer {
|
impl WatchexecFilterer {
|
||||||
/// Create a new filterer from the given arguments
|
/// Create a new filterer from the given arguments
|
||||||
pub async fn new(args: &Args) -> Result<Arc<Self>> {
|
pub async fn new(args: &Args) -> Result<Arc<Self>> {
|
||||||
let project_origin = args.project_origin.clone().unwrap();
|
let (project_origin, workdir) = dirs::dirs(args).await?;
|
||||||
let workdir = args.workdir.clone().unwrap();
|
|
||||||
|
|
||||||
let ignore_files = if args.no_discover_ignore {
|
let ignore_files = if args.no_discover_ignore {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
} else {
|
} else {
|
||||||
let vcs_types = crate::dirs::vcs_types(&project_origin).await;
|
let vcs_types = dirs::vcs_types(&project_origin).await;
|
||||||
crate::dirs::ignores(args, &vcs_types).await?
|
dirs::ignores(args, &vcs_types, &project_origin).await?
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ignores = Vec::new();
|
let mut ignores = Vec::new();
|
||||||
@ -105,12 +105,6 @@ impl WatchexecFilterer {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let whitelist = args
|
|
||||||
.paths
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.into())
|
|
||||||
.filter(|p: &PathBuf| p.is_file());
|
|
||||||
|
|
||||||
let mut filters = args
|
let mut filters = args
|
||||||
.filter_patterns
|
.filter_patterns
|
||||||
.iter()
|
.iter()
|
||||||
@ -134,16 +128,9 @@ impl WatchexecFilterer {
|
|||||||
|
|
||||||
info!("initialising Globset filterer");
|
info!("initialising Globset filterer");
|
||||||
Ok(Arc::new(Self {
|
Ok(Arc::new(Self {
|
||||||
inner: GlobsetFilterer::new(
|
inner: GlobsetFilterer::new(project_origin, filters, ignores, ignore_files, exts)
|
||||||
project_origin,
|
.await
|
||||||
filters,
|
.into_diagnostic()?,
|
||||||
ignores,
|
|
||||||
whitelist,
|
|
||||||
ignore_files,
|
|
||||||
exts,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.into_diagnostic()?,
|
|
||||||
fs_events: args.filter_fs_events.clone(),
|
fs_events: args.filter_fs_events.clone(),
|
||||||
progs: if args.filter_programs_parsed.is_empty() {
|
progs: if args.filter_programs_parsed.is_empty() {
|
||||||
None
|
None
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
borrow::Cow,
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
|
env,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12,7 +14,16 @@ use watchexec::paths::common_prefix;
|
|||||||
|
|
||||||
use crate::args::Args;
|
use crate::args::Args;
|
||||||
|
|
||||||
pub async fn project_origin(args: &Args) -> Result<PathBuf> {
|
type ProjectOriginPath = PathBuf;
|
||||||
|
type WorkDirPath = PathBuf;
|
||||||
|
|
||||||
|
/// Extract relevant directories (in particular the project origin and work directory)
|
||||||
|
/// given the command line arguments that were provided
|
||||||
|
pub async fn dirs(args: &Args) -> Result<(ProjectOriginPath, WorkDirPath)> {
|
||||||
|
let curdir = env::current_dir().into_diagnostic()?;
|
||||||
|
let curdir = canonicalize(curdir).await.into_diagnostic()?;
|
||||||
|
debug!(?curdir, "current directory");
|
||||||
|
|
||||||
let project_origin = if let Some(origin) = &args.project_origin {
|
let project_origin = if let Some(origin) = &args.project_origin {
|
||||||
debug!(?origin, "project origin override");
|
debug!(?origin, "project origin override");
|
||||||
canonicalize(origin).await.into_diagnostic()?
|
canonicalize(origin).await.into_diagnostic()?
|
||||||
@ -23,19 +34,27 @@ pub async fn project_origin(args: &Args) -> Result<PathBuf> {
|
|||||||
};
|
};
|
||||||
debug!(?homedir, "home directory");
|
debug!(?homedir, "home directory");
|
||||||
|
|
||||||
let homedir_requested = homedir.as_ref().map_or(false, |home| {
|
let mut paths = HashSet::new();
|
||||||
args.paths
|
for path in &args.paths {
|
||||||
.binary_search_by_key(home, |w| PathBuf::from(w.clone()))
|
paths.insert(canonicalize(path).await.into_diagnostic()?);
|
||||||
.is_ok()
|
}
|
||||||
});
|
|
||||||
|
let homedir_requested = homedir.as_ref().map_or(false, |home| paths.contains(home));
|
||||||
debug!(
|
debug!(
|
||||||
?homedir_requested,
|
?homedir_requested,
|
||||||
"resolved whether the homedir is explicitly requested"
|
"resolved whether the homedir is explicitly requested"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if paths.is_empty() {
|
||||||
|
debug!("no paths, using current directory");
|
||||||
|
paths.insert(curdir.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!(?paths, "resolved all watched paths");
|
||||||
|
|
||||||
let mut origins = HashSet::new();
|
let mut origins = HashSet::new();
|
||||||
for path in &args.paths {
|
for path in paths {
|
||||||
origins.extend(project_origins::origins(path).await);
|
origins.extend(project_origins::origins(&path).await);
|
||||||
}
|
}
|
||||||
|
|
||||||
match (homedir, homedir_requested) {
|
match (homedir, homedir_requested) {
|
||||||
@ -48,7 +67,7 @@ pub async fn project_origin(args: &Args) -> Result<PathBuf> {
|
|||||||
|
|
||||||
if origins.is_empty() {
|
if origins.is_empty() {
|
||||||
debug!("no origins, using current directory");
|
debug!("no origins, using current directory");
|
||||||
origins.insert(args.workdir.clone().unwrap());
|
origins.insert(curdir.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(?origins, "resolved all project origins");
|
debug!(?origins, "resolved all project origins");
|
||||||
@ -61,9 +80,12 @@ pub async fn project_origin(args: &Args) -> Result<PathBuf> {
|
|||||||
.await
|
.await
|
||||||
.into_diagnostic()?
|
.into_diagnostic()?
|
||||||
};
|
};
|
||||||
debug!(?project_origin, "resolved common/project origin");
|
info!(?project_origin, "resolved common/project origin");
|
||||||
|
|
||||||
Ok(project_origin)
|
let workdir = curdir;
|
||||||
|
info!(?workdir, "resolved working directory");
|
||||||
|
|
||||||
|
Ok((project_origin, workdir))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn vcs_types(origin: &Path) -> Vec<ProjectType> {
|
pub async fn vcs_types(origin: &Path) -> Vec<ProjectType> {
|
||||||
@ -72,34 +94,41 @@ pub async fn vcs_types(origin: &Path) -> Vec<ProjectType> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|pt| pt.is_vcs())
|
.filter(|pt| pt.is_vcs())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
info!(?vcs_types, "effective vcs types");
|
info!(?vcs_types, "resolved vcs types");
|
||||||
vcs_types
|
vcs_types
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn ignores(args: &Args, vcs_types: &[ProjectType]) -> Result<Vec<IgnoreFile>> {
|
pub async fn ignores(
|
||||||
let origin = args.project_origin.clone().unwrap();
|
args: &Args,
|
||||||
|
vcs_types: &[ProjectType],
|
||||||
|
origin: &Path,
|
||||||
|
) -> Result<Vec<IgnoreFile>> {
|
||||||
|
fn higher_make_absolute_if_needed<'a>(
|
||||||
|
origin: &'a Path,
|
||||||
|
) -> impl 'a + Fn(&'a PathBuf) -> Cow<'a, Path> {
|
||||||
|
|path| {
|
||||||
|
if path.is_absolute() {
|
||||||
|
Cow::Borrowed(path)
|
||||||
|
} else {
|
||||||
|
Cow::Owned(origin.join(path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut skip_git_global_excludes = false;
|
let mut skip_git_global_excludes = false;
|
||||||
|
|
||||||
let mut ignores = if args.no_project_ignore {
|
let mut ignores = if args.no_project_ignore {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
} else {
|
} else {
|
||||||
let ignore_files = args.ignore_files.iter().map(|path| {
|
let make_absolute_if_needed = higher_make_absolute_if_needed(origin);
|
||||||
if path.is_absolute() {
|
let include_paths = args.paths.iter().map(&make_absolute_if_needed);
|
||||||
path.into()
|
let ignore_files = args.ignore_files.iter().map(&make_absolute_if_needed);
|
||||||
} else {
|
|
||||||
origin.join(path)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let (mut ignores, errors) = ignore_files::from_origin(
|
let (mut ignores, errors) = ignore_files::from_origin(
|
||||||
IgnoreFilesFromOriginArgs::new_unchecked(
|
IgnoreFilesFromOriginArgs::new_unchecked(origin, include_paths, ignore_files)
|
||||||
&origin,
|
.canonicalise()
|
||||||
args.paths.iter().map(PathBuf::from),
|
.await
|
||||||
ignore_files,
|
.into_diagnostic()?,
|
||||||
)
|
|
||||||
.canonicalise()
|
|
||||||
.await
|
|
||||||
.into_diagnostic()?,
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@ -192,7 +221,7 @@ pub async fn ignores(args: &Args, vcs_types: &[ProjectType]) -> Result<Vec<Ignor
|
|||||||
.filter(|ig| {
|
.filter(|ig| {
|
||||||
!ig.applies_in
|
!ig.applies_in
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(false, |p| p.starts_with(&origin))
|
.map_or(false, |p| p.starts_with(origin))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
debug!(
|
debug!(
|
@ -10,7 +10,7 @@ pub fn parse_filter_program((n, prog): (usize, String)) -> Result<jaq_syn::Main>
|
|||||||
.map(|err| err.to_string())
|
.map(|err| err.to_string())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
return Err(miette!("{}", errs).wrap_err(format!("failed to load filter program #{}", n)));
|
return Err(miette!("failed to load filter program #{}: {:?}", n, errs));
|
||||||
}
|
}
|
||||||
|
|
||||||
main.ok_or_else(|| miette!("failed to load filter program #{} (no reason given)", n))
|
main.ok_or_else(|| miette!("failed to load filter program #{} (no reason given)", n))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![deny(rust_2018_idioms)]
|
#![deny(rust_2018_idioms)]
|
||||||
#![allow(clippy::missing_const_for_fn, clippy::future_not_send)]
|
#![allow(clippy::missing_const_for_fn, clippy::future_not_send)]
|
||||||
|
|
||||||
use std::{io::Write, process::Stdio};
|
use std::{env::var, fs::File, io::Write, process::Stdio, sync::Mutex};
|
||||||
|
|
||||||
use args::{Args, ShellCompletion};
|
use args::{Args, ShellCompletion};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
@ -9,8 +9,8 @@ use clap_complete::{Generator, Shell};
|
|||||||
use clap_mangen::Man;
|
use clap_mangen::Man;
|
||||||
use is_terminal::IsTerminal;
|
use is_terminal::IsTerminal;
|
||||||
use miette::{IntoDiagnostic, Result};
|
use miette::{IntoDiagnostic, Result};
|
||||||
use tokio::{io::AsyncWriteExt, process::Command};
|
use tokio::{fs::metadata, io::AsyncWriteExt, process::Command};
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info, warn};
|
||||||
use watchexec::Watchexec;
|
use watchexec::Watchexec;
|
||||||
use watchexec_events::{Event, Priority};
|
use watchexec_events::{Event, Priority};
|
||||||
|
|
||||||
@ -18,11 +18,86 @@ use crate::filterer::WatchexecFilterer;
|
|||||||
|
|
||||||
pub mod args;
|
pub mod args;
|
||||||
mod config;
|
mod config;
|
||||||
mod dirs;
|
|
||||||
mod emits;
|
mod emits;
|
||||||
mod filterer;
|
mod filterer;
|
||||||
mod state;
|
mod state;
|
||||||
|
|
||||||
|
async fn init() -> Result<Args> {
|
||||||
|
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}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let args = args::get_args().await?;
|
||||||
|
let verbosity = args.verbose.unwrap_or(0);
|
||||||
|
|
||||||
|
if log_on {
|
||||||
|
warn!("ignoring logging options from args");
|
||||||
|
} else if verbosity > 0 {
|
||||||
|
let log_file = if let Some(file) = &args.log_file {
|
||||||
|
let is_dir = metadata(&file).await.map_or(false, |info| info.is_dir());
|
||||||
|
let path = if is_dir {
|
||||||
|
let filename = format!(
|
||||||
|
"watchexec.{}.log",
|
||||||
|
chrono::Utc::now().format("%Y-%m-%dT%H-%M-%SZ")
|
||||||
|
);
|
||||||
|
file.join(filename)
|
||||||
|
} else {
|
||||||
|
file.to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: use tracing-appender instead
|
||||||
|
Some(File::create(path).into_diagnostic()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut builder = tracing_subscriber::fmt().with_env_filter(match verbosity {
|
||||||
|
0 => unreachable!("checked by if earlier"),
|
||||||
|
1 => "warn",
|
||||||
|
2 => "info",
|
||||||
|
3 => "debug",
|
||||||
|
_ => "trace",
|
||||||
|
});
|
||||||
|
|
||||||
|
if verbosity > 2 {
|
||||||
|
use tracing_subscriber::fmt::format::FmtSpan;
|
||||||
|
builder = builder.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
match if let Some(writer) = log_file {
|
||||||
|
builder.json().with_writer(Mutex::new(writer)).try_init()
|
||||||
|
} else if verbosity > 3 {
|
||||||
|
builder.pretty().try_init()
|
||||||
|
} else {
|
||||||
|
builder.try_init()
|
||||||
|
} {
|
||||||
|
Ok(()) => info!("logging initialised"),
|
||||||
|
Err(e) => eprintln!("Failed to initialise logging, continuing with none\n{e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(args)
|
||||||
|
}
|
||||||
|
|
||||||
async fn run_watchexec(args: Args) -> Result<()> {
|
async fn run_watchexec(args: Args) -> Result<()> {
|
||||||
info!(version=%env!("CARGO_PKG_VERSION"), "constructing Watchexec from CLI");
|
info!(version=%env!("CARGO_PKG_VERSION"), "constructing Watchexec from CLI");
|
||||||
|
|
||||||
@ -116,7 +191,8 @@ async fn run_completions(shell: ShellCompletion) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run() -> Result<()> {
|
pub async fn run() -> Result<()> {
|
||||||
let (args, _log_guard) = args::get_args().await?;
|
let args = init().await?;
|
||||||
|
debug!(?args, "arguments");
|
||||||
|
|
||||||
if args.manual {
|
if args.manual {
|
||||||
run_manpage(args).await
|
run_manpage(args).await
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<assemblyIdentity
|
<assemblyIdentity
|
||||||
type="win32"
|
type="win32"
|
||||||
name="Watchexec.Cli.watchexec"
|
name="Watchexec.Cli.watchexec"
|
||||||
version="2.1.2.0"
|
version="1.25.1.0"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<trustInfo>
|
<trustInfo>
|
||||||
|
@ -2,14 +2,6 @@
|
|||||||
|
|
||||||
## Next (YYYY-MM-DD)
|
## Next (YYYY-MM-DD)
|
||||||
|
|
||||||
## v4.0.1 (2024-04-28)
|
|
||||||
|
|
||||||
- Hide fmt::Debug spew from ignore crate, use `full_debug` feature to restore.
|
|
||||||
|
|
||||||
## v4.0.0 (2024-04-20)
|
|
||||||
|
|
||||||
- Deps: watchexec 4
|
|
||||||
|
|
||||||
## v3.0.0 (2024-01-01)
|
## v3.0.0 (2024-01-01)
|
||||||
|
|
||||||
- Deps: `watchexec-filterer-ignore` and `ignore-files`
|
- Deps: `watchexec-filterer-ignore` and `ignore-files`
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "watchexec-filterer-globset"
|
name = "watchexec-filterer-globset"
|
||||||
version = "4.0.1"
|
version = "3.0.0"
|
||||||
|
|
||||||
authors = ["Matt Green <mattgreenrocks@gmail.com>", "Félix Saparelli <felix@passcod.name>"]
|
authors = ["Matt Green <mattgreenrocks@gmail.com>", "Félix Saparelli <felix@passcod.name>"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
@ -20,11 +20,11 @@ ignore = "0.4.18"
|
|||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
|
|
||||||
[dependencies.ignore-files]
|
[dependencies.ignore-files]
|
||||||
version = "3.0.1"
|
version = "3.0.0"
|
||||||
path = "../../ignore-files"
|
path = "../../ignore-files"
|
||||||
|
|
||||||
[dependencies.watchexec]
|
[dependencies.watchexec]
|
||||||
version = "4.1.0"
|
version = "4.0.0"
|
||||||
path = "../../lib"
|
path = "../../lib"
|
||||||
|
|
||||||
[dependencies.watchexec-events]
|
[dependencies.watchexec-events]
|
||||||
@ -32,12 +32,11 @@ version = "3.0.0"
|
|||||||
path = "../../events"
|
path = "../../events"
|
||||||
|
|
||||||
[dependencies.watchexec-filterer-ignore]
|
[dependencies.watchexec-filterer-ignore]
|
||||||
version = "4.0.1"
|
version = "3.0.1"
|
||||||
path = "../ignore"
|
path = "../ignore"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tracing-subscriber = "0.3.6"
|
tracing-subscriber = "0.3.6"
|
||||||
tempfile = "3"
|
|
||||||
|
|
||||||
[dev-dependencies.tokio]
|
[dev-dependencies.tokio]
|
||||||
version = "1.33.0"
|
version = "1.33.0"
|
||||||
@ -48,9 +47,3 @@ features = [
|
|||||||
"rt-multi-thread",
|
"rt-multi-thread",
|
||||||
"macros",
|
"macros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
## Don't hide ignore::gitignore::Gitignore Debug impl
|
|
||||||
full_debug = []
|
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
fmt,
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -22,38 +21,22 @@ use watchexec_events::{Event, FileType, Priority};
|
|||||||
use watchexec_filterer_ignore::IgnoreFilterer;
|
use watchexec_filterer_ignore::IgnoreFilterer;
|
||||||
|
|
||||||
/// A simple filterer in the style of the watchexec v1.17 filter.
|
/// A simple filterer in the style of the watchexec v1.17 filter.
|
||||||
#[cfg_attr(feature = "full_debug", derive(Debug))]
|
#[derive(Debug)]
|
||||||
pub struct GlobsetFilterer {
|
pub struct GlobsetFilterer {
|
||||||
#[cfg_attr(not(unix), allow(dead_code))]
|
#[cfg_attr(not(unix), allow(dead_code))]
|
||||||
origin: PathBuf,
|
origin: PathBuf,
|
||||||
filters: Gitignore,
|
filters: Gitignore,
|
||||||
ignores: Gitignore,
|
ignores: Gitignore,
|
||||||
whitelist: Vec<PathBuf>,
|
|
||||||
ignore_files: IgnoreFilterer,
|
ignore_files: IgnoreFilterer,
|
||||||
extensions: Vec<OsString>,
|
extensions: Vec<OsString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "full_debug"))]
|
|
||||||
impl fmt::Debug for GlobsetFilterer {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("GlobsetFilterer")
|
|
||||||
.field("origin", &self.origin)
|
|
||||||
.field("filters", &"ignore::gitignore::Gitignore{...}")
|
|
||||||
.field("ignores", &"ignore::gitignore::Gitignore{...}")
|
|
||||||
.field("ignore_files", &self.ignore_files)
|
|
||||||
.field("extensions", &self.extensions)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GlobsetFilterer {
|
impl GlobsetFilterer {
|
||||||
/// Create a new `GlobsetFilterer` from a project origin, allowed extensions, and lists of globs.
|
/// Create a new `GlobsetFilterer` from a project origin, allowed extensions, and lists of globs.
|
||||||
///
|
///
|
||||||
/// The first list is used to filter paths (only matching paths will pass the filter), the
|
/// The first list is used to filter paths (only matching paths will pass the filter), the
|
||||||
/// second is used to ignore paths (matching paths will fail the pattern). If the filter list is
|
/// second is used to ignore paths (matching paths will fail the pattern). If the filter list is
|
||||||
/// empty, only the ignore list will be used. If both lists are empty, the filter always passes.
|
/// empty, only the ignore list will be used. If both lists are empty, the filter always passes.
|
||||||
/// Whitelist is used to automatically accept files even if they would be filtered out
|
|
||||||
/// otherwise. It is passed as an absolute path to the file that should not be filtered.
|
|
||||||
///
|
///
|
||||||
/// Ignores and filters are passed as a tuple of the glob pattern as a string and an optional
|
/// Ignores and filters are passed as a tuple of the glob pattern as a string and an optional
|
||||||
/// path of the folder the pattern should apply in (e.g. the folder a gitignore file is in).
|
/// path of the folder the pattern should apply in (e.g. the folder a gitignore file is in).
|
||||||
@ -67,7 +50,6 @@ impl GlobsetFilterer {
|
|||||||
origin: impl AsRef<Path>,
|
origin: impl AsRef<Path>,
|
||||||
filters: impl IntoIterator<Item = (String, Option<PathBuf>)>,
|
filters: impl IntoIterator<Item = (String, Option<PathBuf>)>,
|
||||||
ignores: impl IntoIterator<Item = (String, Option<PathBuf>)>,
|
ignores: impl IntoIterator<Item = (String, Option<PathBuf>)>,
|
||||||
whitelist: impl IntoIterator<Item = PathBuf>,
|
|
||||||
ignore_files: impl IntoIterator<Item = IgnoreFile>,
|
ignore_files: impl IntoIterator<Item = IgnoreFile>,
|
||||||
extensions: impl IntoIterator<Item = OsString>,
|
extensions: impl IntoIterator<Item = OsString>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
@ -103,8 +85,6 @@ impl GlobsetFilterer {
|
|||||||
ignore_files.finish();
|
ignore_files.finish();
|
||||||
let ignore_files = IgnoreFilterer(ignore_files);
|
let ignore_files = IgnoreFilterer(ignore_files);
|
||||||
|
|
||||||
let whitelist = whitelist.into_iter().collect::<Vec<_>>();
|
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
?origin,
|
?origin,
|
||||||
num_filters=%filters.num_ignores(),
|
num_filters=%filters.num_ignores(),
|
||||||
@ -119,7 +99,6 @@ impl GlobsetFilterer {
|
|||||||
origin: origin.into(),
|
origin: origin.into(),
|
||||||
filters,
|
filters,
|
||||||
ignores,
|
ignores,
|
||||||
whitelist,
|
|
||||||
ignore_files,
|
ignore_files,
|
||||||
extensions,
|
extensions,
|
||||||
})
|
})
|
||||||
@ -133,19 +112,6 @@ impl Filterer for GlobsetFilterer {
|
|||||||
fn check_event(&self, event: &Event, priority: Priority) -> Result<bool, RuntimeError> {
|
fn check_event(&self, event: &Event, priority: Priority) -> Result<bool, RuntimeError> {
|
||||||
let _span = trace_span!("filterer_check").entered();
|
let _span = trace_span!("filterer_check").entered();
|
||||||
|
|
||||||
{
|
|
||||||
trace!("checking internal whitelist");
|
|
||||||
// Ideally check path equality backwards for better perf
|
|
||||||
// There could be long matching prefixes so we will exit late
|
|
||||||
if event
|
|
||||||
.paths()
|
|
||||||
.any(|(p, _)| self.whitelist.iter().any(|w| w == p))
|
|
||||||
{
|
|
||||||
trace!("internal whitelist filterer matched (success)");
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
trace!("checking internal ignore filterer");
|
trace!("checking internal ignore filterer");
|
||||||
if !self
|
if !self
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
mod helpers;
|
mod helpers;
|
||||||
use helpers::globset::*;
|
use helpers::globset::*;
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn empty_filter_passes_everything() {
|
async fn empty_filter_passes_everything() {
|
||||||
let filterer = filt(&[], &[], &[], &[], &[]).await;
|
let filterer = filt(&[], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.toml");
|
filterer.file_does_pass("Cargo.toml");
|
||||||
filterer.file_does_pass("Cargo.json");
|
filterer.file_does_pass("Cargo.json");
|
||||||
@ -24,7 +23,7 @@ async fn empty_filter_passes_everything() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn exact_filename() {
|
async fn exact_filename() {
|
||||||
let filterer = filt(&["Cargo.toml"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["Cargo.toml"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.toml");
|
filterer.file_does_pass("Cargo.toml");
|
||||||
filterer.file_does_pass("/test/foo/bar/Cargo.toml");
|
filterer.file_does_pass("/test/foo/bar/Cargo.toml");
|
||||||
@ -37,7 +36,7 @@ async fn exact_filename() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn exact_filename_in_folder() {
|
async fn exact_filename_in_folder() {
|
||||||
let filterer = filt(&["sub/Cargo.toml"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["sub/Cargo.toml"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_doesnt_pass("Cargo.toml");
|
filterer.file_doesnt_pass("Cargo.toml");
|
||||||
filterer.file_does_pass("sub/Cargo.toml");
|
filterer.file_does_pass("sub/Cargo.toml");
|
||||||
@ -51,7 +50,7 @@ async fn exact_filename_in_folder() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn exact_filename_in_hidden_folder() {
|
async fn exact_filename_in_hidden_folder() {
|
||||||
let filterer = filt(&[".sub/Cargo.toml"], &[], &[], &[], &[]).await;
|
let filterer = filt(&[".sub/Cargo.toml"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_doesnt_pass("Cargo.toml");
|
filterer.file_doesnt_pass("Cargo.toml");
|
||||||
filterer.file_does_pass(".sub/Cargo.toml");
|
filterer.file_does_pass(".sub/Cargo.toml");
|
||||||
@ -65,7 +64,7 @@ async fn exact_filename_in_hidden_folder() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn exact_filenames_multiple() {
|
async fn exact_filenames_multiple() {
|
||||||
let filterer = filt(&["Cargo.toml", "package.json"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["Cargo.toml", "package.json"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.toml");
|
filterer.file_does_pass("Cargo.toml");
|
||||||
filterer.file_does_pass("/test/foo/bar/Cargo.toml");
|
filterer.file_does_pass("/test/foo/bar/Cargo.toml");
|
||||||
@ -82,7 +81,7 @@ async fn exact_filenames_multiple() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn glob_single_final_ext_star() {
|
async fn glob_single_final_ext_star() {
|
||||||
let filterer = filt(&["Cargo.*"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["Cargo.*"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.toml");
|
filterer.file_does_pass("Cargo.toml");
|
||||||
filterer.file_does_pass("Cargo.json");
|
filterer.file_does_pass("Cargo.json");
|
||||||
@ -94,7 +93,7 @@ async fn glob_single_final_ext_star() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn glob_star_trailing_slash() {
|
async fn glob_star_trailing_slash() {
|
||||||
let filterer = filt(&["Cargo.*/"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["Cargo.*/"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_doesnt_pass("Cargo.toml");
|
filterer.file_doesnt_pass("Cargo.toml");
|
||||||
filterer.file_doesnt_pass("Cargo.json");
|
filterer.file_doesnt_pass("Cargo.json");
|
||||||
@ -107,7 +106,7 @@ async fn glob_star_trailing_slash() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn glob_star_leading_slash() {
|
async fn glob_star_leading_slash() {
|
||||||
let filterer = filt(&["/Cargo.*"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["/Cargo.*"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.toml");
|
filterer.file_does_pass("Cargo.toml");
|
||||||
filterer.file_does_pass("Cargo.json");
|
filterer.file_does_pass("Cargo.json");
|
||||||
@ -119,7 +118,7 @@ async fn glob_star_leading_slash() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn glob_leading_double_star() {
|
async fn glob_leading_double_star() {
|
||||||
let filterer = filt(&["**/possum"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["**/possum"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("possum");
|
filterer.file_does_pass("possum");
|
||||||
filterer.file_does_pass("foo/bar/possum");
|
filterer.file_does_pass("foo/bar/possum");
|
||||||
@ -134,7 +133,7 @@ async fn glob_leading_double_star() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn glob_trailing_double_star() {
|
async fn glob_trailing_double_star() {
|
||||||
let filterer = filt(&["possum/**"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["possum/**"], &[], &[]).await;
|
||||||
|
|
||||||
// these do work by expectation and in v1
|
// these do work by expectation and in v1
|
||||||
filterer.file_does_pass("/test/possum/foo/bar");
|
filterer.file_does_pass("/test/possum/foo/bar");
|
||||||
@ -148,7 +147,7 @@ async fn glob_trailing_double_star() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn glob_middle_double_star() {
|
async fn glob_middle_double_star() {
|
||||||
let filterer = filt(&["apples/**/oranges"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["apples/**/oranges"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.dir_doesnt_pass("/a/folder");
|
filterer.dir_doesnt_pass("/a/folder");
|
||||||
filterer.file_does_pass("apples/carrots/oranges");
|
filterer.file_does_pass("apples/carrots/oranges");
|
||||||
@ -163,7 +162,7 @@ async fn glob_middle_double_star() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn glob_double_star_trailing_slash() {
|
async fn glob_double_star_trailing_slash() {
|
||||||
let filterer = filt(&["apples/**/oranges/"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["apples/**/oranges/"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.dir_doesnt_pass("/a/folder");
|
filterer.dir_doesnt_pass("/a/folder");
|
||||||
filterer.file_doesnt_pass("apples/carrots/oranges");
|
filterer.file_doesnt_pass("apples/carrots/oranges");
|
||||||
@ -181,7 +180,7 @@ async fn glob_double_star_trailing_slash() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_exact_filename() {
|
async fn ignore_exact_filename() {
|
||||||
let filterer = filt(&[], &["Cargo.toml"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["Cargo.toml"], &[]).await;
|
||||||
|
|
||||||
filterer.file_doesnt_pass("Cargo.toml");
|
filterer.file_doesnt_pass("Cargo.toml");
|
||||||
filterer.file_doesnt_pass("/test/foo/bar/Cargo.toml");
|
filterer.file_doesnt_pass("/test/foo/bar/Cargo.toml");
|
||||||
@ -194,7 +193,7 @@ async fn ignore_exact_filename() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_exact_filename_in_folder() {
|
async fn ignore_exact_filename_in_folder() {
|
||||||
let filterer = filt(&[], &["sub/Cargo.toml"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["sub/Cargo.toml"], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.toml");
|
filterer.file_does_pass("Cargo.toml");
|
||||||
filterer.file_doesnt_pass("sub/Cargo.toml");
|
filterer.file_doesnt_pass("sub/Cargo.toml");
|
||||||
@ -208,7 +207,7 @@ async fn ignore_exact_filename_in_folder() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_exact_filename_in_hidden_folder() {
|
async fn ignore_exact_filename_in_hidden_folder() {
|
||||||
let filterer = filt(&[], &[".sub/Cargo.toml"], &[], &[], &[]).await;
|
let filterer = filt(&[], &[".sub/Cargo.toml"], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.toml");
|
filterer.file_does_pass("Cargo.toml");
|
||||||
filterer.file_doesnt_pass(".sub/Cargo.toml");
|
filterer.file_doesnt_pass(".sub/Cargo.toml");
|
||||||
@ -222,7 +221,7 @@ async fn ignore_exact_filename_in_hidden_folder() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_exact_filenames_multiple() {
|
async fn ignore_exact_filenames_multiple() {
|
||||||
let filterer = filt(&[], &["Cargo.toml", "package.json"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["Cargo.toml", "package.json"], &[]).await;
|
||||||
|
|
||||||
filterer.file_doesnt_pass("Cargo.toml");
|
filterer.file_doesnt_pass("Cargo.toml");
|
||||||
filterer.file_doesnt_pass("/test/foo/bar/Cargo.toml");
|
filterer.file_doesnt_pass("/test/foo/bar/Cargo.toml");
|
||||||
@ -239,7 +238,7 @@ async fn ignore_exact_filenames_multiple() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_glob_single_final_ext_star() {
|
async fn ignore_glob_single_final_ext_star() {
|
||||||
let filterer = filt(&[], &["Cargo.*"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["Cargo.*"], &[]).await;
|
||||||
|
|
||||||
filterer.file_doesnt_pass("Cargo.toml");
|
filterer.file_doesnt_pass("Cargo.toml");
|
||||||
filterer.file_doesnt_pass("Cargo.json");
|
filterer.file_doesnt_pass("Cargo.json");
|
||||||
@ -251,7 +250,7 @@ async fn ignore_glob_single_final_ext_star() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_glob_star_trailing_slash() {
|
async fn ignore_glob_star_trailing_slash() {
|
||||||
let filterer = filt(&[], &["Cargo.*/"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["Cargo.*/"], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.toml");
|
filterer.file_does_pass("Cargo.toml");
|
||||||
filterer.file_does_pass("Cargo.json");
|
filterer.file_does_pass("Cargo.json");
|
||||||
@ -264,7 +263,7 @@ async fn ignore_glob_star_trailing_slash() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_glob_star_leading_slash() {
|
async fn ignore_glob_star_leading_slash() {
|
||||||
let filterer = filt(&[], &["/Cargo.*"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["/Cargo.*"], &[]).await;
|
||||||
|
|
||||||
filterer.file_doesnt_pass("Cargo.toml");
|
filterer.file_doesnt_pass("Cargo.toml");
|
||||||
filterer.file_doesnt_pass("Cargo.json");
|
filterer.file_doesnt_pass("Cargo.json");
|
||||||
@ -276,7 +275,7 @@ async fn ignore_glob_star_leading_slash() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_glob_leading_double_star() {
|
async fn ignore_glob_leading_double_star() {
|
||||||
let filterer = filt(&[], &["**/possum"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["**/possum"], &[]).await;
|
||||||
|
|
||||||
filterer.file_doesnt_pass("possum");
|
filterer.file_doesnt_pass("possum");
|
||||||
filterer.file_doesnt_pass("foo/bar/possum");
|
filterer.file_doesnt_pass("foo/bar/possum");
|
||||||
@ -291,7 +290,7 @@ async fn ignore_glob_leading_double_star() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_glob_trailing_double_star() {
|
async fn ignore_glob_trailing_double_star() {
|
||||||
let filterer = filt(&[], &["possum/**"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["possum/**"], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("possum");
|
filterer.file_does_pass("possum");
|
||||||
filterer.file_doesnt_pass("possum/foo/bar");
|
filterer.file_doesnt_pass("possum/foo/bar");
|
||||||
@ -310,7 +309,7 @@ async fn ignore_glob_trailing_double_star() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_glob_middle_double_star() {
|
async fn ignore_glob_middle_double_star() {
|
||||||
let filterer = filt(&[], &["apples/**/oranges"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["apples/**/oranges"], &[]).await;
|
||||||
|
|
||||||
filterer.dir_does_pass("/a/folder");
|
filterer.dir_does_pass("/a/folder");
|
||||||
filterer.file_doesnt_pass("apples/carrots/oranges");
|
filterer.file_doesnt_pass("apples/carrots/oranges");
|
||||||
@ -325,7 +324,7 @@ async fn ignore_glob_middle_double_star() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_glob_double_star_trailing_slash() {
|
async fn ignore_glob_double_star_trailing_slash() {
|
||||||
let filterer = filt(&[], &["apples/**/oranges/"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["apples/**/oranges/"], &[]).await;
|
||||||
|
|
||||||
filterer.dir_does_pass("/a/folder");
|
filterer.dir_does_pass("/a/folder");
|
||||||
filterer.file_does_pass("apples/carrots/oranges");
|
filterer.file_does_pass("apples/carrots/oranges");
|
||||||
@ -343,14 +342,7 @@ async fn ignore_glob_double_star_trailing_slash() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignores_take_precedence() {
|
async fn ignores_take_precedence() {
|
||||||
let filterer = filt(
|
let filterer = filt(&["*.docx", "*.toml", "*.json"], &["*.toml", "*.json"], &[]).await;
|
||||||
&["*.docx", "*.toml", "*.json"],
|
|
||||||
&["*.toml", "*.json"],
|
|
||||||
&[],
|
|
||||||
&[],
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
filterer.file_doesnt_pass("Cargo.toml");
|
filterer.file_doesnt_pass("Cargo.toml");
|
||||||
filterer.file_doesnt_pass("/test/foo/bar/Cargo.toml");
|
filterer.file_doesnt_pass("/test/foo/bar/Cargo.toml");
|
||||||
@ -363,7 +355,7 @@ async fn ignores_take_precedence() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extensions_fail_dirs() {
|
async fn extensions_fail_dirs() {
|
||||||
let filterer = filt(&[], &[], &[], &["py"], &[]).await;
|
let filterer = filt(&[], &[], &["py"]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.py");
|
filterer.file_does_pass("Cargo.py");
|
||||||
filterer.file_doesnt_pass("Cargo.toml");
|
filterer.file_doesnt_pass("Cargo.toml");
|
||||||
@ -374,7 +366,7 @@ async fn extensions_fail_dirs() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extensions_fail_extensionless() {
|
async fn extensions_fail_extensionless() {
|
||||||
let filterer = filt(&[], &[], &[], &["py"], &[]).await;
|
let filterer = filt(&[], &[], &["py"]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("Cargo.py");
|
filterer.file_does_pass("Cargo.py");
|
||||||
filterer.file_doesnt_pass("Cargo");
|
filterer.file_doesnt_pass("Cargo");
|
||||||
@ -385,7 +377,7 @@ async fn multipath_allow_on_any_one_pass() {
|
|||||||
use watchexec::filter::Filterer;
|
use watchexec::filter::Filterer;
|
||||||
use watchexec_events::{Event, FileType, Tag};
|
use watchexec_events::{Event, FileType, Tag};
|
||||||
|
|
||||||
let filterer = filt(&[], &[], &[], &["py"], &[]).await;
|
let filterer = filt(&[], &[], &["py"]).await;
|
||||||
let origin = tokio::fs::canonicalize(".").await.unwrap();
|
let origin = tokio::fs::canonicalize(".").await.unwrap();
|
||||||
|
|
||||||
let event = Event {
|
let event = Event {
|
||||||
@ -411,7 +403,7 @@ async fn multipath_allow_on_any_one_pass() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extensions_and_filters_glob() {
|
async fn extensions_and_filters_glob() {
|
||||||
let filterer = filt(&["*/justfile"], &[], &[], &["md", "css"], &[]).await;
|
let filterer = filt(&["*/justfile"], &[], &["md", "css"]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("foo/justfile");
|
filterer.file_does_pass("foo/justfile");
|
||||||
filterer.file_does_pass("bar.md");
|
filterer.file_does_pass("bar.md");
|
||||||
@ -425,7 +417,7 @@ async fn extensions_and_filters_glob() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn extensions_and_filters_slash() {
|
async fn extensions_and_filters_slash() {
|
||||||
let filterer = filt(&["/justfile"], &[], &[], &["md", "css"], &[]).await;
|
let filterer = filt(&["/justfile"], &[], &["md", "css"]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("justfile");
|
filterer.file_does_pass("justfile");
|
||||||
filterer.file_does_pass("bar.md");
|
filterer.file_does_pass("bar.md");
|
||||||
@ -435,7 +427,7 @@ async fn extensions_and_filters_slash() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn leading_single_glob_file() {
|
async fn leading_single_glob_file() {
|
||||||
let filterer = filt(&["*/justfile"], &[], &[], &[], &[]).await;
|
let filterer = filt(&["*/justfile"], &[], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("foo/justfile");
|
filterer.file_does_pass("foo/justfile");
|
||||||
filterer.file_doesnt_pass("notfile");
|
filterer.file_doesnt_pass("notfile");
|
||||||
@ -451,7 +443,7 @@ async fn nonpath_event_passes() {
|
|||||||
use watchexec::filter::Filterer;
|
use watchexec::filter::Filterer;
|
||||||
use watchexec_events::{Event, Source, Tag};
|
use watchexec_events::{Event, Source, Tag};
|
||||||
|
|
||||||
let filterer = filt(&[], &[], &[], &["py"], &[]).await;
|
let filterer = filt(&[], &[], &["py"]).await;
|
||||||
|
|
||||||
assert!(filterer
|
assert!(filterer
|
||||||
.check_event(
|
.check_event(
|
||||||
@ -478,7 +470,7 @@ async fn nonpath_event_passes() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_folder_incorrectly_with_bare_match() {
|
async fn ignore_folder_incorrectly_with_bare_match() {
|
||||||
let filterer = filt(&[], &["prunes"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["prunes"], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("apples");
|
filterer.file_does_pass("apples");
|
||||||
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
||||||
@ -509,7 +501,7 @@ async fn ignore_folder_incorrectly_with_bare_match() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_folder_incorrectly_with_bare_and_leading_slash() {
|
async fn ignore_folder_incorrectly_with_bare_and_leading_slash() {
|
||||||
let filterer = filt(&[], &["/prunes"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["/prunes"], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("apples");
|
filterer.file_does_pass("apples");
|
||||||
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
||||||
@ -540,7 +532,7 @@ async fn ignore_folder_incorrectly_with_bare_and_leading_slash() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_folder_incorrectly_with_bare_and_trailing_slash() {
|
async fn ignore_folder_incorrectly_with_bare_and_trailing_slash() {
|
||||||
let filterer = filt(&[], &["prunes/"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["prunes/"], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("apples");
|
filterer.file_does_pass("apples");
|
||||||
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
||||||
@ -571,7 +563,7 @@ async fn ignore_folder_incorrectly_with_bare_and_trailing_slash() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_folder_incorrectly_with_only_double_double_glob() {
|
async fn ignore_folder_incorrectly_with_only_double_double_glob() {
|
||||||
let filterer = filt(&[], &["**/prunes/**"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["**/prunes/**"], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("apples");
|
filterer.file_does_pass("apples");
|
||||||
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
||||||
@ -602,7 +594,7 @@ async fn ignore_folder_incorrectly_with_only_double_double_glob() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn ignore_folder_correctly_with_double_and_double_double_globs() {
|
async fn ignore_folder_correctly_with_double_and_double_double_globs() {
|
||||||
let filterer = filt(&[], &["**/prunes", "**/prunes/**"], &[], &[], &[]).await;
|
let filterer = filt(&[], &["**/prunes", "**/prunes/**"], &[]).await;
|
||||||
|
|
||||||
filterer.file_does_pass("apples");
|
filterer.file_does_pass("apples");
|
||||||
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
filterer.file_does_pass("apples/carrots/cauliflowers/oranges");
|
||||||
@ -628,94 +620,3 @@ async fn ignore_folder_correctly_with_double_and_double_double_globs() {
|
|||||||
filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/oranges");
|
filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/oranges");
|
||||||
filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges");
|
filterer.dir_doesnt_pass("prunes/carrots/cauliflowers/artichokes/oranges");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn whitelist_overrides_ignore() {
|
|
||||||
let filterer = filt(&[], &["**/prunes"], &["/prunes"], &[], &[]).await;
|
|
||||||
|
|
||||||
filterer.file_does_pass("apples");
|
|
||||||
filterer.file_does_pass("/prunes");
|
|
||||||
filterer.dir_does_pass("apples");
|
|
||||||
filterer.dir_does_pass("/prunes");
|
|
||||||
|
|
||||||
filterer.file_does_pass("raw-prunes");
|
|
||||||
filterer.dir_does_pass("raw-prunes");
|
|
||||||
|
|
||||||
filterer.file_doesnt_pass("apples/prunes");
|
|
||||||
filterer.file_doesnt_pass("raw/prunes");
|
|
||||||
filterer.dir_doesnt_pass("apples/prunes");
|
|
||||||
filterer.dir_doesnt_pass("raw/prunes");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn whitelist_overrides_ignore_files() {
|
|
||||||
let mut ignore_file = tempfile::NamedTempFile::new().unwrap();
|
|
||||||
let _ = ignore_file.write(b"prunes");
|
|
||||||
|
|
||||||
let origin = std::fs::canonicalize(".").unwrap();
|
|
||||||
let whitelist = origin.join("prunes").display().to_string();
|
|
||||||
|
|
||||||
let filterer = filt(
|
|
||||||
&[],
|
|
||||||
&[],
|
|
||||||
&[&whitelist],
|
|
||||||
&[],
|
|
||||||
&[ignore_file.path().to_path_buf()],
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
filterer.file_does_pass("apples");
|
|
||||||
filterer.file_does_pass("prunes");
|
|
||||||
filterer.dir_does_pass("apples");
|
|
||||||
filterer.dir_does_pass("prunes");
|
|
||||||
|
|
||||||
filterer.file_does_pass("raw-prunes");
|
|
||||||
filterer.dir_does_pass("raw-prunes");
|
|
||||||
|
|
||||||
filterer.file_doesnt_pass("apples/prunes");
|
|
||||||
filterer.file_doesnt_pass("raw/prunes");
|
|
||||||
filterer.dir_doesnt_pass("apples/prunes");
|
|
||||||
filterer.dir_doesnt_pass("raw/prunes");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn whitelist_overrides_ignore_files_nested() {
|
|
||||||
let mut ignore_file = tempfile::NamedTempFile::new().unwrap();
|
|
||||||
let _ = ignore_file.write(b"prunes\n");
|
|
||||||
|
|
||||||
let origin = std::fs::canonicalize(".").unwrap();
|
|
||||||
let whitelist = origin.join("prunes").join("target").display().to_string();
|
|
||||||
|
|
||||||
let filterer = filt(
|
|
||||||
&[],
|
|
||||||
&[],
|
|
||||||
&[&whitelist],
|
|
||||||
&[],
|
|
||||||
&[ignore_file.path().to_path_buf()],
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
filterer.file_does_pass("apples");
|
|
||||||
filterer.file_doesnt_pass("prunes");
|
|
||||||
filterer.dir_does_pass("apples");
|
|
||||||
filterer.dir_doesnt_pass("prunes");
|
|
||||||
|
|
||||||
filterer.file_does_pass("raw-prunes");
|
|
||||||
filterer.dir_does_pass("raw-prunes");
|
|
||||||
|
|
||||||
filterer.file_doesnt_pass("prunes/apples");
|
|
||||||
filterer.file_doesnt_pass("prunes/raw");
|
|
||||||
filterer.dir_doesnt_pass("prunes/apples");
|
|
||||||
filterer.dir_doesnt_pass("prunes/raw");
|
|
||||||
|
|
||||||
filterer.file_doesnt_pass("apples/prunes");
|
|
||||||
filterer.file_doesnt_pass("raw/prunes");
|
|
||||||
filterer.dir_doesnt_pass("apples/prunes");
|
|
||||||
filterer.dir_doesnt_pass("raw/prunes");
|
|
||||||
|
|
||||||
filterer.file_does_pass("prunes/target");
|
|
||||||
filterer.dir_does_pass("prunes/target");
|
|
||||||
|
|
||||||
filterer.file_doesnt_pass("prunes/nested/target");
|
|
||||||
filterer.dir_doesnt_pass("prunes/nested/target");
|
|
||||||
}
|
|
||||||
|
@ -3,7 +3,6 @@ use std::{
|
|||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ignore_files::IgnoreFile;
|
|
||||||
use watchexec::{error::RuntimeError, filter::Filterer};
|
use watchexec::{error::RuntimeError, filter::Filterer};
|
||||||
use watchexec_events::{Event, FileType, Priority, Tag};
|
use watchexec_events::{Event, FileType, Priority, Tag};
|
||||||
use watchexec_filterer_globset::GlobsetFilterer;
|
use watchexec_filterer_globset::GlobsetFilterer;
|
||||||
@ -103,9 +102,7 @@ fn tracing_init() {
|
|||||||
pub async fn globset_filt(
|
pub async fn globset_filt(
|
||||||
filters: &[&str],
|
filters: &[&str],
|
||||||
ignores: &[&str],
|
ignores: &[&str],
|
||||||
whitelists: &[&str],
|
|
||||||
extensions: &[&str],
|
extensions: &[&str],
|
||||||
ignore_files: &[PathBuf],
|
|
||||||
) -> GlobsetFilterer {
|
) -> GlobsetFilterer {
|
||||||
let origin = tokio::fs::canonicalize(".").await.unwrap();
|
let origin = tokio::fs::canonicalize(".").await.unwrap();
|
||||||
tracing_init();
|
tracing_init();
|
||||||
@ -113,12 +110,7 @@ pub async fn globset_filt(
|
|||||||
origin,
|
origin,
|
||||||
filters.iter().map(|s| ((*s).to_string(), None)),
|
filters.iter().map(|s| ((*s).to_string(), None)),
|
||||||
ignores.iter().map(|s| ((*s).to_string(), None)),
|
ignores.iter().map(|s| ((*s).to_string(), None)),
|
||||||
whitelists.iter().map(|s| (*s).into()),
|
vec![],
|
||||||
ignore_files.iter().map(|path| IgnoreFile {
|
|
||||||
path: path.clone(),
|
|
||||||
applies_in: None,
|
|
||||||
applies_to: None,
|
|
||||||
}),
|
|
||||||
extensions.iter().map(OsString::from),
|
extensions.iter().map(OsString::from),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
## Next (YYYY-MM-DD)
|
## Next (YYYY-MM-DD)
|
||||||
|
|
||||||
## v4.0.1 (2024-04-28)
|
|
||||||
|
|
||||||
## v4.0.0 (2024-04-20)
|
|
||||||
|
|
||||||
- Deps: watchexec 4
|
|
||||||
|
|
||||||
## v3.0.1 (2024-01-04)
|
## v3.0.1 (2024-01-04)
|
||||||
|
|
||||||
- Normalise paths on all platforms (via `normalize-path`).
|
- Normalise paths on all platforms (via `normalize-path`).
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "watchexec-filterer-ignore"
|
name = "watchexec-filterer-ignore"
|
||||||
version = "4.0.1"
|
version = "3.0.1"
|
||||||
|
|
||||||
authors = ["Félix Saparelli <felix@passcod.name>"]
|
authors = ["Félix Saparelli <felix@passcod.name>"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
@ -22,11 +22,11 @@ normalize-path = "0.2.1"
|
|||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
|
|
||||||
[dependencies.ignore-files]
|
[dependencies.ignore-files]
|
||||||
version = "3.0.1"
|
version = "3.0.0"
|
||||||
path = "../../ignore-files"
|
path = "../../ignore-files"
|
||||||
|
|
||||||
[dependencies.watchexec]
|
[dependencies.watchexec]
|
||||||
version = "4.1.0"
|
version = "4.0.0"
|
||||||
path = "../../lib"
|
path = "../../lib"
|
||||||
|
|
||||||
[dependencies.watchexec-events]
|
[dependencies.watchexec-events]
|
||||||
@ -41,7 +41,7 @@ path = "../../signals"
|
|||||||
tracing-subscriber = "0.3.6"
|
tracing-subscriber = "0.3.6"
|
||||||
|
|
||||||
[dev-dependencies.project-origins]
|
[dev-dependencies.project-origins]
|
||||||
version = "1.4.0"
|
version = "1.3.0"
|
||||||
path = "../../project-origins"
|
path = "../../project-origins"
|
||||||
|
|
||||||
[dev-dependencies.tokio]
|
[dev-dependencies.tokio]
|
||||||
|
@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
## Next (YYYY-MM-DD)
|
## Next (YYYY-MM-DD)
|
||||||
|
|
||||||
## v3.0.1 (2024-04-28)
|
|
||||||
|
|
||||||
- Hide fmt::Debug spew from ignore crate, use `full_debug` feature to restore.
|
|
||||||
|
|
||||||
## v3.0.0 (2024-04-20)
|
## v3.0.0 (2024-04-20)
|
||||||
|
|
||||||
- Deps: gix-config 0.36
|
- Deps: gix-config 0.36
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ignore-files"
|
name = "ignore-files"
|
||||||
version = "3.0.1"
|
version = "3.0.0"
|
||||||
|
|
||||||
authors = ["Félix Saparelli <felix@passcod.name>"]
|
authors = ["Félix Saparelli <felix@passcod.name>"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
@ -35,14 +35,8 @@ features = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[dependencies.project-origins]
|
[dependencies.project-origins]
|
||||||
version = "1.4.0"
|
version = "1.3.0"
|
||||||
path = "../project-origins"
|
path = "../project-origins"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tracing-subscriber = "0.3.6"
|
tracing-subscriber = "0.3.6"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
## Don't hide ignore::gitignore::Gitignore Debug impl
|
|
||||||
full_debug = []
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use std::fmt;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use futures::stream::{FuturesUnordered, StreamExt};
|
use futures::stream::{FuturesUnordered, StreamExt};
|
||||||
@ -12,23 +11,12 @@ use tracing::{trace, trace_span};
|
|||||||
|
|
||||||
use crate::{simplify_path, Error, IgnoreFile};
|
use crate::{simplify_path, Error, IgnoreFile};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
#[cfg_attr(feature = "full_debug", derive(Debug))]
|
|
||||||
struct Ignore {
|
struct Ignore {
|
||||||
gitignore: Gitignore,
|
gitignore: Gitignore,
|
||||||
builder: Option<GitignoreBuilder>,
|
builder: Option<GitignoreBuilder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "full_debug"))]
|
|
||||||
impl fmt::Debug for Ignore {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("Ignore")
|
|
||||||
.field("gitignore", &"ignore::gitignore::Gitignore{...}")
|
|
||||||
.field("builder", &"ignore::gitignore::GitignoreBuilder{...}")
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A mutable filter dedicated to ignore files and trees of ignore files.
|
/// A mutable filter dedicated to ignore files and trees of ignore files.
|
||||||
///
|
///
|
||||||
/// This reads and compiles ignore files, and should be used for handling ignore files. It's created
|
/// This reads and compiles ignore files, and should be used for handling ignore files. It's created
|
||||||
|
@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
## Next (YYYY-MM-DD)
|
## Next (YYYY-MM-DD)
|
||||||
|
|
||||||
## v4.1.0 (2024-04-28)
|
|
||||||
|
|
||||||
- Feature: non-recursive watches with `WatchedPath::non_recursive()`
|
|
||||||
- Fix: `config.pathset()` now preserves `WatchedPath` attributes
|
|
||||||
- Refactor: move `WatchedPath` to the root of the crate (old path remains as re-export for now)
|
|
||||||
|
|
||||||
## v4.0.0 (2024-04-20)
|
## v4.0.0 (2024-04-20)
|
||||||
|
|
||||||
- Deps: replace command-group with process-wrap (in supervisor, but has flow-on effects)
|
- Deps: replace command-group with process-wrap (in supervisor, but has flow-on effects)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "watchexec"
|
name = "watchexec"
|
||||||
version = "4.1.0"
|
version = "4.0.0"
|
||||||
|
|
||||||
authors = ["Félix Saparelli <felix@passcod.name>", "Matt Green <mattgreenrocks@gmail.com>"]
|
authors = ["Félix Saparelli <felix@passcod.name>", "Matt Green <mattgreenrocks@gmail.com>"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
@ -43,11 +43,11 @@ version = "2.0.0"
|
|||||||
path = "../supervisor"
|
path = "../supervisor"
|
||||||
|
|
||||||
[dependencies.ignore-files]
|
[dependencies.ignore-files]
|
||||||
version = "3.0.1"
|
version = "3.0.0"
|
||||||
path = "../ignore-files"
|
path = "../ignore-files"
|
||||||
|
|
||||||
[dependencies.project-origins]
|
[dependencies.project-origins]
|
||||||
version = "1.4.0"
|
version = "1.3.0"
|
||||||
path = "../project-origins"
|
path = "../project-origins"
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Configuration and builders for [`crate::Watchexec`].
|
//! Configuration and builders for [`crate::Watchexec`].
|
||||||
|
|
||||||
use std::{future::Future, pin::pin, sync::Arc, time::Duration};
|
use std::{future::Future, path::Path, pin::pin, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use tokio::sync::Notify;
|
use tokio::sync::Notify;
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
@ -195,9 +195,9 @@ impl Config {
|
|||||||
pub fn pathset<I, P>(&self, pathset: I) -> &Self
|
pub fn pathset<I, P>(&self, pathset: I) -> &Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = P>,
|
I: IntoIterator<Item = P>,
|
||||||
P: Into<WatchedPath>,
|
P: AsRef<Path>,
|
||||||
{
|
{
|
||||||
let pathset = pathset.into_iter().map(|p| p.into()).collect();
|
let pathset = pathset.into_iter().map(|p| p.as_ref().into()).collect();
|
||||||
debug!(?pathset, "Config: pathset");
|
debug!(?pathset, "Config: pathset");
|
||||||
self.pathset.replace(pathset);
|
self.pathset.replace(pathset);
|
||||||
self.signal_change()
|
self.signal_change()
|
||||||
|
@ -68,13 +68,11 @@ pub mod config;
|
|||||||
|
|
||||||
mod id;
|
mod id;
|
||||||
mod late_join_set;
|
mod late_join_set;
|
||||||
mod watched_path;
|
|
||||||
mod watchexec;
|
mod watchexec;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
id::Id,
|
id::Id,
|
||||||
watched_path::WatchedPath,
|
|
||||||
watchexec::{ErrorHook, Watchexec},
|
watchexec::{ErrorHook, Watchexec},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ use std::{
|
|||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
fs::metadata,
|
fs::metadata,
|
||||||
mem::take,
|
mem::take,
|
||||||
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
@ -19,9 +20,6 @@ use crate::{
|
|||||||
Config,
|
Config,
|
||||||
};
|
};
|
||||||
|
|
||||||
// re-export for compatibility, until next major version
|
|
||||||
pub use crate::WatchedPath;
|
|
||||||
|
|
||||||
/// What kind of filesystem watcher to use.
|
/// What kind of filesystem watcher to use.
|
||||||
///
|
///
|
||||||
/// For now only native and poll watchers are supported. In the future there may be additional
|
/// For now only native and poll watchers are supported. In the future there may be additional
|
||||||
@ -74,6 +72,42 @@ impl Watcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A path to watch.
|
||||||
|
///
|
||||||
|
/// This is currently only a wrapper around a [`PathBuf`], but may be augmented in the future.
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct WatchedPath(PathBuf);
|
||||||
|
|
||||||
|
impl From<PathBuf> for WatchedPath {
|
||||||
|
fn from(path: PathBuf) -> Self {
|
||||||
|
Self(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for WatchedPath {
|
||||||
|
fn from(path: &str) -> Self {
|
||||||
|
Self(path.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Path> for WatchedPath {
|
||||||
|
fn from(path: &Path) -> Self {
|
||||||
|
Self(path.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<WatchedPath> for PathBuf {
|
||||||
|
fn from(path: WatchedPath) -> Self {
|
||||||
|
path.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Path> for WatchedPath {
|
||||||
|
fn as_ref(&self) -> &Path {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Launch the filesystem event worker.
|
/// Launch the filesystem event worker.
|
||||||
///
|
///
|
||||||
/// While you can run several, you should only have one.
|
/// While you can run several, you should only have one.
|
||||||
@ -156,7 +190,6 @@ pub async fn worker(
|
|||||||
// now let's calculate which paths we should add to the watch, and which we should drop:
|
// now let's calculate which paths we should add to the watch, and which we should drop:
|
||||||
|
|
||||||
let config_pathset = config.pathset.get();
|
let config_pathset = config.pathset.get();
|
||||||
tracing::info!(?config_pathset, "obtaining pathset");
|
|
||||||
let (to_watch, to_drop) = if pathset.is_empty() {
|
let (to_watch, to_drop) = if pathset.is_empty() {
|
||||||
// if the current pathset is empty, we can take a shortcut
|
// if the current pathset is empty, we can take a shortcut
|
||||||
(config_pathset, Vec::new())
|
(config_pathset, Vec::new())
|
||||||
@ -189,7 +222,7 @@ pub async fn worker(
|
|||||||
|
|
||||||
for path in to_drop {
|
for path in to_drop {
|
||||||
trace!(?path, "removing path from the watcher");
|
trace!(?path, "removing path from the watcher");
|
||||||
if let Err(err) = watcher.unwatch(path.path.as_ref()) {
|
if let Err(err) = watcher.unwatch(path.as_ref()) {
|
||||||
error!(?err, "notify unwatch() error");
|
error!(?err, "notify unwatch() error");
|
||||||
for e in notify_multi_path_errors(watcher_type, path, err, true) {
|
for e in notify_multi_path_errors(watcher_type, path, err, true) {
|
||||||
errors.send(e).await?;
|
errors.send(e).await?;
|
||||||
@ -201,18 +234,13 @@ pub async fn worker(
|
|||||||
|
|
||||||
for path in to_watch {
|
for path in to_watch {
|
||||||
trace!(?path, "adding path to the watcher");
|
trace!(?path, "adding path to the watcher");
|
||||||
if let Err(err) = watcher.watch(
|
if let Err(err) = watcher.watch(path.as_ref(), notify::RecursiveMode::Recursive) {
|
||||||
path.path.as_ref(),
|
|
||||||
if path.recursive {
|
|
||||||
notify::RecursiveMode::Recursive
|
|
||||||
} else {
|
|
||||||
notify::RecursiveMode::NonRecursive
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
error!(?err, "notify watch() error");
|
error!(?err, "notify watch() error");
|
||||||
for e in notify_multi_path_errors(watcher_type, path, err, false) {
|
for e in notify_multi_path_errors(watcher_type, path, err, false) {
|
||||||
errors.send(e).await?;
|
errors.send(e).await?;
|
||||||
}
|
}
|
||||||
|
// TODO: unwatch and re-watch manually while ignoring all the erroring paths
|
||||||
|
// See https://github.com/watchexec/watchexec/issues/218
|
||||||
} else {
|
} else {
|
||||||
pathset.insert(path);
|
pathset.insert(path);
|
||||||
}
|
}
|
||||||
@ -222,13 +250,13 @@ pub async fn worker(
|
|||||||
|
|
||||||
fn notify_multi_path_errors(
|
fn notify_multi_path_errors(
|
||||||
kind: Watcher,
|
kind: Watcher,
|
||||||
watched_path: WatchedPath,
|
path: WatchedPath,
|
||||||
mut err: notify::Error,
|
mut err: notify::Error,
|
||||||
rm: bool,
|
rm: bool,
|
||||||
) -> Vec<RuntimeError> {
|
) -> Vec<RuntimeError> {
|
||||||
let mut paths = take(&mut err.paths);
|
let mut paths = take(&mut err.paths);
|
||||||
if paths.is_empty() {
|
if paths.is_empty() {
|
||||||
paths.push(watched_path.into());
|
paths.push(path.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let generic = err.to_string();
|
let generic = err.to_string();
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
/// A path to watch.
|
|
||||||
///
|
|
||||||
/// Can be a recursive or non-recursive watch.
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
||||||
pub struct WatchedPath {
|
|
||||||
pub(crate) path: PathBuf,
|
|
||||||
pub(crate) recursive: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<PathBuf> for WatchedPath {
|
|
||||||
fn from(path: PathBuf) -> Self {
|
|
||||||
Self {
|
|
||||||
path,
|
|
||||||
recursive: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for WatchedPath {
|
|
||||||
fn from(path: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
path: path.into(),
|
|
||||||
recursive: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for WatchedPath {
|
|
||||||
fn from(path: String) -> Self {
|
|
||||||
Self {
|
|
||||||
path: path.into(),
|
|
||||||
recursive: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Path> for WatchedPath {
|
|
||||||
fn from(path: &Path) -> Self {
|
|
||||||
Self {
|
|
||||||
path: path.into(),
|
|
||||||
recursive: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<WatchedPath> for PathBuf {
|
|
||||||
fn from(path: WatchedPath) -> Self {
|
|
||||||
path.path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&WatchedPath> for PathBuf {
|
|
||||||
fn from(path: &WatchedPath) -> Self {
|
|
||||||
path.path.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<Path> for WatchedPath {
|
|
||||||
fn as_ref(&self) -> &Path {
|
|
||||||
self.path.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WatchedPath {
|
|
||||||
/// Create a new watched path, recursively descending into subdirectories.
|
|
||||||
pub fn recursive(path: impl Into<PathBuf>) -> Self {
|
|
||||||
Self {
|
|
||||||
path: path.into(),
|
|
||||||
recursive: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new watched path, not descending into subdirectories.
|
|
||||||
pub fn non_recursive(path: impl Into<PathBuf>) -> Self {
|
|
||||||
Self {
|
|
||||||
path: path.into(),
|
|
||||||
recursive: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
## Next (YYYY-MM-DD)
|
## Next (YYYY-MM-DD)
|
||||||
|
|
||||||
## v1.4.0 (2024-04-28)
|
|
||||||
|
|
||||||
- Add out-of-tree Git repositories (`.git` file instead of folder).
|
|
||||||
|
|
||||||
## v1.3.0 (2024-01-01)
|
## v1.3.0 (2024-01-01)
|
||||||
|
|
||||||
- Remove `README.md` files from detection; those were causing too many false positives and were a weak signal anyway.
|
- Remove `README.md` files from detection; those were causing too many false positives and were a weak signal anyway.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "project-origins"
|
name = "project-origins"
|
||||||
version = "1.4.0"
|
version = "1.3.0"
|
||||||
|
|
||||||
authors = ["Félix Saparelli <felix@passcod.name>"]
|
authors = ["Félix Saparelli <felix@passcod.name>"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
@ -49,7 +49,7 @@ pub enum ProjectType {
|
|||||||
|
|
||||||
/// VCS: [Git](https://git-scm.com/).
|
/// VCS: [Git](https://git-scm.com/).
|
||||||
///
|
///
|
||||||
/// Detects when a `.git` file or folder is present, or any of the files `.gitattributes` or
|
/// Detects when a `.git` folder is present, or any of the files `.gitattributes` or
|
||||||
/// `.gitmodules`. Does _not_ check or return from the presence of `.gitignore` files, as Git
|
/// `.gitmodules`. Does _not_ check or return from the presence of `.gitignore` files, as Git
|
||||||
/// supports nested ignores, and that would result in false-positives.
|
/// supports nested ignores, and that would result in false-positives.
|
||||||
Git,
|
Git,
|
||||||
@ -208,7 +208,6 @@ pub async fn origins(path: impl AsRef<Path> + Send) -> HashSet<PathBuf> {
|
|||||||
list.has_file(".codecov.yml"),
|
list.has_file(".codecov.yml"),
|
||||||
list.has_file(".ctags"),
|
list.has_file(".ctags"),
|
||||||
list.has_file(".editorconfig"),
|
list.has_file(".editorconfig"),
|
||||||
list.has_file(".git"),
|
|
||||||
list.has_file(".gitattributes"),
|
list.has_file(".gitattributes"),
|
||||||
list.has_file(".gitmodules"),
|
list.has_file(".gitmodules"),
|
||||||
list.has_file(".hgignore"),
|
list.has_file(".hgignore"),
|
||||||
@ -294,7 +293,6 @@ pub async fn types(path: impl AsRef<Path> + Send) -> HashSet<ProjectType> {
|
|||||||
list.if_has_dir(".svn", ProjectType::Subversion),
|
list.if_has_dir(".svn", ProjectType::Subversion),
|
||||||
list.if_has_file(".bzrignore", ProjectType::Bazaar),
|
list.if_has_file(".bzrignore", ProjectType::Bazaar),
|
||||||
list.if_has_file(".ctags", ProjectType::C),
|
list.if_has_file(".ctags", ProjectType::C),
|
||||||
list.if_has_file(".git", ProjectType::Git),
|
|
||||||
list.if_has_file(".gitattributes", ProjectType::Git),
|
list.if_has_file(".gitattributes", ProjectType::Git),
|
||||||
list.if_has_file(".gitmodules", ProjectType::Git),
|
list.if_has_file(".gitmodules", ProjectType::Git),
|
||||||
list.if_has_file(".hgignore", ProjectType::Mercurial),
|
list.if_has_file(".hgignore", ProjectType::Mercurial),
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
.ie \n(.g .ds Aq \(aq
|
.ie \n(.g .ds Aq \(aq
|
||||||
.el .ds Aq '
|
.el .ds Aq '
|
||||||
.TH watchexec 1 "watchexec 2.1.2"
|
.TH watchexec 1 "watchexec 1.25.1"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
watchexec \- Execute commands when watched files change
|
watchexec \- Execute commands when watched files change
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
\fBwatchexec\fR [\fB\-w\fR|\fB\-\-watch\fR] [\fB\-W\fR|\fB\-\-watch\-non\-recursive\fR] [\fB\-F\fR|\fB\-\-watch\-file\fR] [\fB\-c\fR|\fB\-\-clear\fR] [\fB\-o\fR|\fB\-\-on\-busy\-update\fR] [\fB\-r\fR|\fB\-\-restart\fR] [\fB\-s\fR|\fB\-\-signal\fR] [\fB\-\-stop\-signal\fR] [\fB\-\-stop\-timeout\fR] [\fB\-\-map\-signal\fR] [\fB\-d\fR|\fB\-\-debounce\fR] [\fB\-\-stdin\-quit\fR] [\fB\-\-no\-vcs\-ignore\fR] [\fB\-\-no\-project\-ignore\fR] [\fB\-\-no\-global\-ignore\fR] [\fB\-\-no\-default\-ignore\fR] [\fB\-\-no\-discover\-ignore\fR] [\fB\-\-ignore\-nothing\fR] [\fB\-p\fR|\fB\-\-postpone\fR] [\fB\-\-delay\-run\fR] [\fB\-\-poll\fR] [\fB\-\-shell\fR] [\fB\-n \fR] [\fB\-\-emit\-events\-to\fR] [\fB\-\-only\-emit\-events\fR] [\fB\-E\fR|\fB\-\-env\fR] [\fB\-\-no\-process\-group\fR] [\fB\-\-wrap\-process\fR] [\fB\-N\fR|\fB\-\-notify\fR] [\fB\-\-color\fR] [\fB\-\-timings\fR] [\fB\-q\fR|\fB\-\-quiet\fR] [\fB\-\-bell\fR] [\fB\-\-project\-origin\fR] [\fB\-\-workdir\fR] [\fB\-e\fR|\fB\-\-exts\fR] [\fB\-f\fR|\fB\-\-filter\fR] [\fB\-\-filter\-file\fR] [\fB\-j\fR|\fB\-\-filter\-prog\fR] [\fB\-i\fR|\fB\-\-ignore\fR] [\fB\-\-ignore\-file\fR] [\fB\-\-fs\-events\fR] [\fB\-\-no\-meta\fR] [\fB\-\-print\-events\fR] [\fB\-\-manual\fR] [\fB\-\-completions\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-\-log\-file\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fICOMMAND\fR]
|
\fBwatchexec\fR [\fB\-w\fR|\fB\-\-watch\fR] [\fB\-c\fR|\fB\-\-clear\fR] [\fB\-o\fR|\fB\-\-on\-busy\-update\fR] [\fB\-r\fR|\fB\-\-restart\fR] [\fB\-s\fR|\fB\-\-signal\fR] [\fB\-\-stop\-signal\fR] [\fB\-\-stop\-timeout\fR] [\fB\-\-map\-signal\fR] [\fB\-d\fR|\fB\-\-debounce\fR] [\fB\-\-stdin\-quit\fR] [\fB\-\-no\-vcs\-ignore\fR] [\fB\-\-no\-project\-ignore\fR] [\fB\-\-no\-global\-ignore\fR] [\fB\-\-no\-default\-ignore\fR] [\fB\-\-no\-discover\-ignore\fR] [\fB\-\-ignore\-nothing\fR] [\fB\-p\fR|\fB\-\-postpone\fR] [\fB\-\-delay\-run\fR] [\fB\-\-poll\fR] [\fB\-\-shell\fR] [\fB\-n \fR] [\fB\-\-emit\-events\-to\fR] [\fB\-\-only\-emit\-events\fR] [\fB\-E\fR|\fB\-\-env\fR] [\fB\-\-no\-process\-group\fR] [\fB\-\-wrap\-process\fR] [\fB\-N\fR|\fB\-\-notify\fR] [\fB\-\-color\fR] [\fB\-\-timings\fR] [\fB\-q\fR|\fB\-\-quiet\fR] [\fB\-\-bell\fR] [\fB\-\-project\-origin\fR] [\fB\-\-workdir\fR] [\fB\-e\fR|\fB\-\-exts\fR] [\fB\-f\fR|\fB\-\-filter\fR] [\fB\-\-filter\-file\fR] [\fB\-j\fR|\fB\-\-filter\-prog\fR] [\fB\-i\fR|\fB\-\-ignore\fR] [\fB\-\-ignore\-file\fR] [\fB\-\-fs\-events\fR] [\fB\-\-no\-meta\fR] [\fB\-\-print\-events\fR] [\fB\-v\fR|\fB\-\-verbose\fR]... [\fB\-\-log\-file\fR] [\fB\-\-manual\fR] [\fB\-\-completions\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fICOMMAND\fR]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Execute commands when watched files change.
|
Execute commands when watched files change.
|
||||||
.PP
|
.PP
|
||||||
@ -48,22 +48,6 @@ This option can be specified multiple times to watch multiple files or directori
|
|||||||
|
|
||||||
The special value \*(Aq/dev/null\*(Aq, provided as the only path watched, will cause Watchexec to not watch any paths. Other event sources (like signals or key events) may still be used.
|
The special value \*(Aq/dev/null\*(Aq, provided as the only path watched, will cause Watchexec to not watch any paths. Other event sources (like signals or key events) may still be used.
|
||||||
.TP
|
.TP
|
||||||
\fB\-W\fR, \fB\-\-watch\-non\-recursive\fR=\fIPATH\fR
|
|
||||||
Watch a specific directory, non\-recursively
|
|
||||||
|
|
||||||
Unlike \*(Aq\-w\*(Aq, folders watched with this option are not recursed into.
|
|
||||||
|
|
||||||
This option can be specified multiple times to watch multiple directories non\-recursively.
|
|
||||||
.TP
|
|
||||||
\fB\-F\fR, \fB\-\-watch\-file\fR=\fIPATH\fR
|
|
||||||
Watch files and directories from a file
|
|
||||||
|
|
||||||
Each line in the file will be interpreted as if given to \*(Aq\-w\*(Aq.
|
|
||||||
|
|
||||||
For more complex uses (like watching non\-recursively), use the argfile capability: build a file containing command\-line options and pass it to watchexec with `@path/to/argfile`.
|
|
||||||
|
|
||||||
The special value \*(Aq\-\*(Aq will read from STDIN; this in incompatible with \*(Aq\-\-stdin\-quit\*(Aq.
|
|
||||||
.TP
|
|
||||||
\fB\-c\fR, \fB\-\-clear\fR=\fIMODE\fR
|
\fB\-c\fR, \fB\-\-clear\fR=\fIMODE\fR
|
||||||
Clear screen before running command
|
Clear screen before running command
|
||||||
|
|
||||||
@ -72,9 +56,11 @@ If this doesn\*(Aqt completely clear the screen, try \*(Aq\-\-clear=reset\*(Aq.
|
|||||||
\fB\-o\fR, \fB\-\-on\-busy\-update\fR=\fIMODE\fR
|
\fB\-o\fR, \fB\-\-on\-busy\-update\fR=\fIMODE\fR
|
||||||
What to do when receiving events while the command is running
|
What to do when receiving events while the command is running
|
||||||
|
|
||||||
Default is to \*(Aqdo\-nothing\*(Aq, which ignores events while the command is running, so that changes that occur due to the command are ignored, like compilation outputs. You can also use \*(Aqqueue\*(Aq which will run the command once again when the current run has finished if any events occur while it\*(Aqs running, or \*(Aqrestart\*(Aq, which terminates the running command and starts a new one. Finally, there\*(Aqs \*(Aqsignal\*(Aq, which only sends a signal; this can be useful with programs that can reload their configuration without a full restart.
|
Default is to \*(Aqqueue\*(Aq up events and run the command once again when the previous run has finished. You can also use \*(Aqdo\-nothing\*(Aq, which ignores events while the command is running and may be useful to avoid spurious changes made by that command, or \*(Aqrestart\*(Aq, which terminates the running command and starts a new one. Finally, there\*(Aqs \*(Aqsignal\*(Aq, which only sends a signal; this can be useful with programs that can reload their configuration without a full restart.
|
||||||
|
|
||||||
The signal can be specified with the \*(Aq\-\-signal\*(Aq option.
|
The signal can be specified with the \*(Aq\-\-signal\*(Aq option.
|
||||||
|
|
||||||
|
Note that this option is scheduled to change its default to \*(Aqdo\-nothing\*(Aq in the next major release. File an issue if you have any concerns.
|
||||||
.TP
|
.TP
|
||||||
\fB\-r\fR, \fB\-\-restart\fR
|
\fB\-r\fR, \fB\-\-restart\fR
|
||||||
Restart the process if it\*(Aqs still running
|
Restart the process if it\*(Aqs still running
|
||||||
@ -455,7 +441,7 @@ This can also be used via the $WATCHEXEC_FILTER_FILES environment variable.
|
|||||||
|
|
||||||
/!\\ This option is EXPERIMENTAL and may change and/or vanish without notice.
|
/!\\ This option is EXPERIMENTAL and may change and/or vanish without notice.
|
||||||
|
|
||||||
Provide your own custom filter programs in jaq (similar to jq) syntax. Programs are given an event in the same format as described in \*(Aq\-\-emit\-events\-to\*(Aq and must return a boolean. Invalid programs will make watchexec fail to start; use \*(Aq\-v\*(Aq to see program runtime errors.
|
Provide your own custom filter programs in jaq (similar to jq) syntax. Programs are given an event in the same format as described in \*(Aq\-\-emit\-events\-to\*(Aq and must return a boolean.
|
||||||
|
|
||||||
In addition to the jaq stdlib, watchexec adds some custom filter definitions:
|
In addition to the jaq stdlib, watchexec adds some custom filter definitions:
|
||||||
|
|
||||||
@ -526,19 +512,7 @@ Print events that trigger actions
|
|||||||
|
|
||||||
This prints the events that triggered the action when handling it (after debouncing), in a human readable form. This is useful for debugging filters.
|
This prints the events that triggered the action when handling it (after debouncing), in a human readable form. This is useful for debugging filters.
|
||||||
|
|
||||||
Use \*(Aq\-vvv\*(Aq instead when you need more diagnostic information.
|
Use \*(Aq\-v\*(Aq when you need more diagnostic information.
|
||||||
.TP
|
|
||||||
\fB\-\-manual\fR
|
|
||||||
Show the manual page
|
|
||||||
|
|
||||||
This shows the manual page for Watchexec, if the output is a terminal and the \*(Aqman\*(Aq program is available. If not, the manual page is printed to stdout in ROFF format (suitable for writing to a watchexec.1 file).
|
|
||||||
.TP
|
|
||||||
\fB\-\-completions\fR=\fICOMPLETIONS\fR
|
|
||||||
Generate a shell completions script
|
|
||||||
|
|
||||||
Provides a completions script or configuration for the given shell. If Watchexec is not distributed with pre\-generated completions, you can use this to generate them yourself.
|
|
||||||
|
|
||||||
Supported shells: bash, elvish, fish, nu, powershell, zsh.
|
|
||||||
.TP
|
.TP
|
||||||
\fB\-v\fR, \fB\-\-verbose\fR
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
Set diagnostic log level
|
Set diagnostic log level
|
||||||
@ -560,6 +534,18 @@ If a path is not provided, the default is the working directory. Note that with
|
|||||||
|
|
||||||
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 \*(Aqwatchexec.YYYY\-MM\-DDTHH\-MM\-SSZ.log\*(Aq.
|
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 \*(Aqwatchexec.YYYY\-MM\-DDTHH\-MM\-SSZ.log\*(Aq.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-manual\fR
|
||||||
|
Show the manual page
|
||||||
|
|
||||||
|
This shows the manual page for Watchexec, if the output is a terminal and the \*(Aqman\*(Aq program is available. If not, the manual page is printed to stdout in ROFF format (suitable for writing to a watchexec.1 file).
|
||||||
|
.TP
|
||||||
|
\fB\-\-completions\fR=\fICOMPLETIONS\fR
|
||||||
|
Generate a shell completions script
|
||||||
|
|
||||||
|
Provides a completions script or configuration for the given shell. If Watchexec is not distributed with pre\-generated completions, you can use this to generate them yourself.
|
||||||
|
|
||||||
|
Supported shells: bash, elvish, fish, nu, powershell, zsh.
|
||||||
|
.TP
|
||||||
\fB\-h\fR, \fB\-\-help\fR
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
Print help (see a summary with \*(Aq\-h\*(Aq)
|
Print help (see a summary with \*(Aq\-h\*(Aq)
|
||||||
.TP
|
.TP
|
||||||
@ -591,6 +577,6 @@ Use @argfile as first argument to load arguments from the file \*(Aqargfile\*(Aq
|
|||||||
|
|
||||||
Didn\*(Aqt expect this much output? Use the short \*(Aq\-h\*(Aq flag to get short help.
|
Didn\*(Aqt expect this much output? Use the short \*(Aq\-h\*(Aq flag to get short help.
|
||||||
.SH VERSION
|
.SH VERSION
|
||||||
v2.1.2
|
v1.25.1
|
||||||
.SH AUTHORS
|
.SH AUTHORS
|
||||||
Félix Saparelli <felix@passcod.name>, Matt Green <mattgreenrocks@gmail.com>
|
Félix Saparelli <felix@passcod.name>, Matt Green <mattgreenrocks@gmail.com>
|
||||||
|
@ -4,12 +4,10 @@ watchexec - Execute commands when watched files change
|
|||||||
|
|
||||||
# SYNOPSIS
|
# SYNOPSIS
|
||||||
|
|
||||||
**watchexec** \[**-w**\|**\--watch**\]
|
**watchexec** \[**-w**\|**\--watch**\] \[**-c**\|**\--clear**\]
|
||||||
\[**-W**\|**\--watch-non-recursive**\] \[**-F**\|**\--watch-file**\]
|
\[**-o**\|**\--on-busy-update**\] \[**-r**\|**\--restart**\]
|
||||||
\[**-c**\|**\--clear**\] \[**-o**\|**\--on-busy-update**\]
|
\[**-s**\|**\--signal**\] \[**\--stop-signal**\] \[**\--stop-timeout**\]
|
||||||
\[**-r**\|**\--restart**\] \[**-s**\|**\--signal**\]
|
\[**\--map-signal**\] \[**-d**\|**\--debounce**\] \[**\--stdin-quit**\]
|
||||||
\[**\--stop-signal**\] \[**\--stop-timeout**\] \[**\--map-signal**\]
|
|
||||||
\[**-d**\|**\--debounce**\] \[**\--stdin-quit**\]
|
|
||||||
\[**\--no-vcs-ignore**\] \[**\--no-project-ignore**\]
|
\[**\--no-vcs-ignore**\] \[**\--no-project-ignore**\]
|
||||||
\[**\--no-global-ignore**\] \[**\--no-default-ignore**\]
|
\[**\--no-global-ignore**\] \[**\--no-default-ignore**\]
|
||||||
\[**\--no-discover-ignore**\] \[**\--ignore-nothing**\]
|
\[**\--no-discover-ignore**\] \[**\--ignore-nothing**\]
|
||||||
@ -22,10 +20,10 @@ watchexec - Execute commands when watched files change
|
|||||||
\[**\--workdir**\] \[**-e**\|**\--exts**\] \[**-f**\|**\--filter**\]
|
\[**\--workdir**\] \[**-e**\|**\--exts**\] \[**-f**\|**\--filter**\]
|
||||||
\[**\--filter-file**\] \[**-j**\|**\--filter-prog**\]
|
\[**\--filter-file**\] \[**-j**\|**\--filter-prog**\]
|
||||||
\[**-i**\|**\--ignore**\] \[**\--ignore-file**\] \[**\--fs-events**\]
|
\[**-i**\|**\--ignore**\] \[**\--ignore-file**\] \[**\--fs-events**\]
|
||||||
\[**\--no-meta**\] \[**\--print-events**\] \[**\--manual**\]
|
\[**\--no-meta**\] \[**\--print-events**\]
|
||||||
\[**\--completions**\] \[**-v**\|**\--verbose**\]\...
|
\[**-v**\|**\--verbose**\]\... \[**\--log-file**\] \[**\--manual**\]
|
||||||
\[**\--log-file**\] \[**-h**\|**\--help**\] \[**-V**\|**\--version**\]
|
\[**\--completions**\] \[**-h**\|**\--help**\]
|
||||||
\[*COMMAND*\]
|
\[**-V**\|**\--version**\] \[*COMMAND*\]
|
||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
@ -84,28 +82,6 @@ The special value /dev/null, provided as the only path watched, will
|
|||||||
cause Watchexec to not watch any paths. Other event sources (like
|
cause Watchexec to not watch any paths. Other event sources (like
|
||||||
signals or key events) may still be used.
|
signals or key events) may still be used.
|
||||||
|
|
||||||
**-W**, **\--watch-non-recursive**=*PATH*
|
|
||||||
|
|
||||||
: Watch a specific directory, non-recursively
|
|
||||||
|
|
||||||
Unlike -w, folders watched with this option are not recursed into.
|
|
||||||
|
|
||||||
This option can be specified multiple times to watch multiple
|
|
||||||
directories non-recursively.
|
|
||||||
|
|
||||||
**-F**, **\--watch-file**=*PATH*
|
|
||||||
|
|
||||||
: Watch files and directories from a file
|
|
||||||
|
|
||||||
Each line in the file will be interpreted as if given to -w.
|
|
||||||
|
|
||||||
For more complex uses (like watching non-recursively), use the argfile
|
|
||||||
capability: build a file containing command-line options and pass it to
|
|
||||||
watchexec with \`@path/to/argfile\`.
|
|
||||||
|
|
||||||
The special value - will read from STDIN; this in incompatible with
|
|
||||||
\--stdin-quit.
|
|
||||||
|
|
||||||
**-c**, **\--clear**=*MODE*
|
**-c**, **\--clear**=*MODE*
|
||||||
|
|
||||||
: Clear screen before running command
|
: Clear screen before running command
|
||||||
@ -116,17 +92,19 @@ If this doesnt completely clear the screen, try \--clear=reset.
|
|||||||
|
|
||||||
: What to do when receiving events while the command is running
|
: What to do when receiving events while the command is running
|
||||||
|
|
||||||
Default is to do-nothing, which ignores events while the command is
|
Default is to queue up events and run the command once again when the
|
||||||
running, so that changes that occur due to the command are ignored, like
|
previous run has finished. You can also use do-nothing, which ignores
|
||||||
compilation outputs. You can also use queue which will run the command
|
events while the command is running and may be useful to avoid spurious
|
||||||
once again when the current run has finished if any events occur while
|
changes made by that command, or restart, which terminates the running
|
||||||
its running, or restart, which terminates the running command and starts
|
command and starts a new one. Finally, theres signal, which only sends a
|
||||||
a new one. Finally, theres signal, which only sends a signal; this can
|
signal; this can be useful with programs that can reload their
|
||||||
be useful with programs that can reload their configuration without a
|
configuration without a full restart.
|
||||||
full restart.
|
|
||||||
|
|
||||||
The signal can be specified with the \--signal option.
|
The signal can be specified with the \--signal option.
|
||||||
|
|
||||||
|
Note that this option is scheduled to change its default to do-nothing
|
||||||
|
in the next major release. File an issue if you have any concerns.
|
||||||
|
|
||||||
**-r**, **\--restart**
|
**-r**, **\--restart**
|
||||||
|
|
||||||
: Restart the process if its still running
|
: Restart the process if its still running
|
||||||
@ -654,8 +632,7 @@ notice.
|
|||||||
|
|
||||||
Provide your own custom filter programs in jaq (similar to jq) syntax.
|
Provide your own custom filter programs in jaq (similar to jq) syntax.
|
||||||
Programs are given an event in the same format as described in
|
Programs are given an event in the same format as described in
|
||||||
\--emit-events-to and must return a boolean. Invalid programs will make
|
\--emit-events-to and must return a boolean.
|
||||||
watchexec fail to start; use -v to see program runtime errors.
|
|
||||||
|
|
||||||
In addition to the jaq stdlib, watchexec adds some custom filter
|
In addition to the jaq stdlib, watchexec adds some custom filter
|
||||||
definitions:
|
definitions:
|
||||||
@ -771,25 +748,7 @@ This prints the events that triggered the action when handling it (after
|
|||||||
debouncing), in a human readable form. This is useful for debugging
|
debouncing), in a human readable form. This is useful for debugging
|
||||||
filters.
|
filters.
|
||||||
|
|
||||||
Use -vvv instead when you need more diagnostic information.
|
Use -v when you need more diagnostic information.
|
||||||
|
|
||||||
**\--manual**
|
|
||||||
|
|
||||||
: Show the manual page
|
|
||||||
|
|
||||||
This shows the manual page for Watchexec, if the output is a terminal
|
|
||||||
and the man program is available. If not, the manual page is printed to
|
|
||||||
stdout in ROFF format (suitable for writing to a watchexec.1 file).
|
|
||||||
|
|
||||||
**\--completions**=*COMPLETIONS*
|
|
||||||
|
|
||||||
: Generate a shell completions script
|
|
||||||
|
|
||||||
Provides a completions script or configuration for the given shell. If
|
|
||||||
Watchexec is not distributed with pre-generated completions, you can use
|
|
||||||
this to generate them yourself.
|
|
||||||
|
|
||||||
Supported shells: bash, elvish, fish, nu, powershell, zsh.
|
|
||||||
|
|
||||||
**-v**, **\--verbose**
|
**-v**, **\--verbose**
|
||||||
|
|
||||||
@ -825,6 +784,24 @@ 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
|
directory. The file name will be the current date and time, in the
|
||||||
format watchexec.YYYY-MM-DDTHH-MM-SSZ.log.
|
format watchexec.YYYY-MM-DDTHH-MM-SSZ.log.
|
||||||
|
|
||||||
|
**\--manual**
|
||||||
|
|
||||||
|
: Show the manual page
|
||||||
|
|
||||||
|
This shows the manual page for Watchexec, if the output is a terminal
|
||||||
|
and the man program is available. If not, the manual page is printed to
|
||||||
|
stdout in ROFF format (suitable for writing to a watchexec.1 file).
|
||||||
|
|
||||||
|
**\--completions**=*COMPLETIONS*
|
||||||
|
|
||||||
|
: Generate a shell completions script
|
||||||
|
|
||||||
|
Provides a completions script or configuration for the given shell. If
|
||||||
|
Watchexec is not distributed with pre-generated completions, you can use
|
||||||
|
this to generate them yourself.
|
||||||
|
|
||||||
|
Supported shells: bash, elvish, fish, nu, powershell, zsh.
|
||||||
|
|
||||||
**-h**, **\--help**
|
**-h**, **\--help**
|
||||||
|
|
||||||
: Print help (see a summary with -h)
|
: Print help (see a summary with -h)
|
||||||
@ -875,7 +852,7 @@ Didnt expect this much output? Use the short -h flag to get short help.
|
|||||||
|
|
||||||
# VERSION
|
# VERSION
|
||||||
|
|
||||||
v2.1.2
|
v1.25.1
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user