stacksdapp_watcher/
lib.rs1use anyhow::Result;
2use notify::{Config, RecommendedWatcher, RecursiveMode, Watcher};
3use std::path::Path;
4use std::time::{Duration, SystemTime, UNIX_EPOCH};
5use tokio::sync::mpsc;
6use tokio::time::timeout;
7
8pub async fn watch_contracts(contracts_dir: &Path) -> Result<()> {
9 let (tx, mut rx) = mpsc::channel(32);
10 let mut watcher = RecommendedWatcher::new(
11 move |res| {
12 let _ = tx.blocking_send(res);
13 },
14 Config::default().with_poll_interval(Duration::from_millis(500)),
15 )?;
16
17 watcher.watch(contracts_dir, RecursiveMode::Recursive)?;
18
19 const DEBOUNCE_MS: u64 = 300;
20
21 while let Some(event) = rx.recv().await {
22 if let Ok(e) = event {
23 if e.paths
24 .iter()
25 .any(|p| p.extension().map(|x| x == "clar").unwrap_or(false))
26 {
27 while let Ok(Some(next_event)) =
29 timeout(Duration::from_millis(DEBOUNCE_MS), rx.recv()).await
30 {
31 if let Ok(next) = next_event {
32 let is_clar_change = next
33 .paths
34 .iter()
35 .any(|p| p.extension().map(|x| x == "clar").unwrap_or(false));
36 if !is_clar_change {
37 continue;
38 }
39 }
40 }
41
42 if let Err(e) = stacksdapp_codegen::generate_all_quiet().await {
43 stacksdapp_shell::error(format!(
44 "[{}] ✗ Contract bindings failed: {e}",
45 timestamp_now()
46 ));
47 } else {
48 stacksdapp_shell::status(format!(
49 "[{}] ✓ Contract bindings updated",
50 timestamp_now()
51 ));
52 }
53 }
54 }
55 }
56
57 Ok(())
58}
59
60fn timestamp_now() -> String {
61 let secs = SystemTime::now()
62 .duration_since(UNIX_EPOCH)
63 .map(|d| d.as_secs())
64 .unwrap_or(0);
65 let hours = (secs / 3600) % 24;
66 let mins = (secs / 60) % 60;
67 let s = secs % 60;
68 format!("{hours:02}:{mins:02}:{s:02}")
69}
70
71#[cfg(test)]
72mod tests {
73 use super::timestamp_now;
74 use stacksdapp_shell::{init, status, ColorMode, Format, Shell};
75
76 #[test]
77 fn watcher_status_respects_quiet_mode() {
78 init(Shell {
79 verbosity: 0,
80 quiet: true,
81 format: Format::Human,
82 color: ColorMode::Never,
83 });
84 status(format!("[{}] ✓ Contract bindings updated", timestamp_now()));
85 }
86}