diff --git a/crates/corrosion/src/command/tpl.rs b/crates/corrosion/src/command/tpl.rs index 481791c6e..91603ecf7 100644 --- a/crates/corrosion/src/command/tpl.rs +++ b/crates/corrosion/src/command/tpl.rs @@ -1,7 +1,9 @@ use std::{ collections::{HashMap, HashSet}, env::current_dir, + io::ErrorKind, net::SocketAddr, + path::Path, time::{Duration, Instant}, }; @@ -131,7 +133,10 @@ pub async fn run( debug!("rendered template"); - tokio::fs::rename(&tmp_filepath, &dst).await?; + if let Err(e) = atomic_rename_or_copy(&tmp_filepath, &dst).await { + error!("failed to write {}: {e}", dst); + break; + } debug!("wrote file"); @@ -226,11 +231,8 @@ pub async fn run( tokio::spawn(async_watch(filepaths)); while let Some(res) = futs.next().await { - match res { - Ok(_) => { - info!("") - } - Err(_) => todo!(), + if let Err(ref err) = res { + error!("template task failed: {err:#}"); } println!("got a res: {res:?}"); } @@ -238,6 +240,20 @@ pub async fn run( Ok(()) } +async fn atomic_rename_or_copy(tmp: &Path, dst: &Utf8PathBuf) -> eyre::Result<()> { + match tokio::fs::rename(tmp, dst).await { + Ok(()) => Ok(()), + Err(e) if e.raw_os_error() == Some(18) => { + // libc::EXDEV cross link + info!("cross-device rename, falling back to copy"); + tokio::fs::copy(tmp, dst).await?; + tokio::fs::remove_file(tmp).await?; + Ok(()) + } + Err(e) => Err(e.into()), + } +} + fn async_watcher() -> notify::Result<(Debouncer, Receiver)> { let (tx, rx) = channel(1);