-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimple-watch-run.py
More file actions
84 lines (73 loc) · 2.23 KB
/
simple-watch-run.py
File metadata and controls
84 lines (73 loc) · 2.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""Re-run a command whenever watched files change."""
import os
import sys
import time
import glob
import argparse
import subprocess
def snapshot(patterns: list[str]) -> dict[str, tuple[float, int]]:
snap: dict[str, tuple[float, int]] = {}
for pattern in patterns:
for path in glob.glob(pattern, recursive=True):
try:
st = os.stat(path)
snap[path] = (st.st_mtime, st.st_size)
except OSError:
pass
return snap
def terminate(proc: subprocess.Popen) -> None: # type: ignore[type-arg]
if proc.poll() is None:
proc.terminate()
try:
proc.wait(timeout=5)
except subprocess.TimeoutExpired:
proc.kill()
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Re-run a command when watched files change.",
epilog='Example: %(prog)s -w "src/**/*.py" -- python app.py',
)
parser.add_argument(
"-w",
"--watch",
nargs="+",
required=True,
metavar="PATTERN",
help="Glob patterns to watch (supports **)",
)
parser.add_argument(
"--interval",
type=float,
default=1.0,
help="Poll interval in seconds (default: 1.0)",
)
parser.add_argument(
"cmd", nargs=argparse.REMAINDER, help="Command to run (after --)"
)
args = parser.parse_args()
cmd = args.cmd
if cmd and cmd[0] == "--":
cmd = cmd[1:]
if not cmd:
parser.error("Provide a command after --")
print(f"Watching : {args.watch}")
print(f"Command : {' '.join(cmd)}")
print("Press Ctrl+C to stop.\n")
snap = snapshot(args.watch)
proc = subprocess.Popen(cmd)
try:
while True:
time.sleep(args.interval)
new = snapshot(args.watch)
if new != snap:
changed = [
p for p in set(list(snap) + list(new)) if snap.get(p) != new.get(p)
]
print(f"\n[changed] {', '.join(changed)}")
snap = new
terminate(proc)
proc = subprocess.Popen(cmd)
except KeyboardInterrupt:
terminate(proc)
print("\nStopped.")
sys.exit(0)