use std::time::{Duration, Instant}; use tokio::fs::{create_dir_all, read_dir, remove_dir, remove_file}; mod merge; mod path_resolve; pub mod process; mod schema_version; pub use merge::deep_merge; pub use path_resolve::resolve_relative_paths; pub use schema_version::{SchemaVersion, SchemaVersionError, VersionedSchema}; pub const READY_FILE_NAME: &str = ".ready"; pub const READY_FILE_TIMEOUT: Duration = Duration::from_secs(30); pub const HEARTBEAT_FILE_NAME: &str = ".heartbeat"; pub const HEARTBEAT_FILE_TIMEOUT: Duration = Duration::from_secs(90); pub const SHUTDOWN_DEADLINE: Duration = Duration::from_secs(5); pub const VERSION: &str = env!("ETV_VERSION_STRING"); pub async fn empty_folder(output_folder: &std::path::Path) -> Result<(), std::io::Error> { if !output_folder.exists() { create_dir_all(output_folder).await?; } let mut entries = read_dir(output_folder).await?; while let Ok(Some(entry)) = entries.next_entry().await { if let Ok(file_type) = entry.file_type().await { if file_type.is_dir() { Box::pin(empty_folder(&entry.path())).await?; remove_dir(entry.path()).await?; } else { remove_file(entry.path()).await?; } } } Ok(()) } pub async fn wait_for_file(path: &std::path::Path, timeout: Duration) -> bool { let deadline = Instant::now() + timeout; loop { if path.exists() { return true; } if Instant::now() >= deadline { return false; } tokio::time::sleep(Duration::from_millis(200)).await } }