From 4438f402591d05e369636f54e18b4bab232702b5 Mon Sep 17 00:00:00 2001 From: Samuel Moelius Date: Mon, 30 Sep 2024 19:56:50 +0000 Subject: [PATCH] Allow driver to to be installed when existing driver is running --- dylint/src/driver_builder.rs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/dylint/src/driver_builder.rs b/dylint/src/driver_builder.rs index ef93fd60d..64636d403 100644 --- a/dylint/src/driver_builder.rs +++ b/dylint/src/driver_builder.rs @@ -9,10 +9,10 @@ use dylint_internal::{ use semver::Version; use std::{ env::consts, - fs::{copy, create_dir_all, write}, + fs::{copy, create_dir_all, rename, write}, path::{Path, PathBuf}, }; -use tempfile::tempdir; +use tempfile::{tempdir, NamedTempFile}; include!(concat!(env!("OUT_DIR"), "/dylint_driver_manifest_dir.rs")); @@ -183,16 +183,29 @@ fn build(opts: &opts::Dylint, toolchain: &str, driver_dir: &Path) -> Result<()> .join("debug") .join(format!("dylint_driver-{toolchain}{}", consts::EXE_SUFFIX)); - let driver = driver_dir.join("dylint-driver"); + let named_temp_file = NamedTempFile::new_in(driver_dir) + .with_context(|| "Could not create temporary directory")?; #[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))] - copy(&binary, &driver).with_context(|| { + copy(&binary, &named_temp_file).with_context(|| { format!( "Could not copy `{binary}` to `{}`", - driver.to_string_lossy() + named_temp_file.path().to_string_lossy() ) })?; + let driver = driver_dir.join("dylint-driver"); + + // smoelius: Windows requires that the old file be moved out of the way first. + if cfg!(target_os = "windows") { + let temp_path = NamedTempFile::new_in(driver_dir) + .map(NamedTempFile::into_temp_path) + .with_context(|| "Could not create temporary directory")?; + rename(&driver, &temp_path).unwrap_or_default(); + } + + named_temp_file.persist(&driver)?; + Ok(()) } @@ -231,7 +244,7 @@ fn initialize(toolchain: &str, package: &Path) -> Result<()> { #[cfg(test)] mod test { use super::*; - use std::process::Command; + use std::process::{Command, ExitStatus}; // smoelius: `tempdir` is a temporary directory. So there should be no race here. #[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))] @@ -241,6 +254,9 @@ mod test { build(&opts::Dylint::default(), "nightly", tempdir.path()).unwrap(); } + // smoelius: As mentioned above, `tempdir` is a temporary directory. So there should be no race + // here. + #[cfg_attr(dylint_lib = "general", allow(non_thread_safe_call_in_test))] #[test] fn can_install_while_driver_is_running() { const WHICH: &str = if cfg!(target_os = "windows") { @@ -266,6 +282,6 @@ mod test { build(&opts::Dylint::default(), "nightly", tempdir.path()).unwrap(); child.kill().unwrap(); - let _: std::process::ExitStatus = child.wait().unwrap(); + let _: ExitStatus = child.wait().unwrap(); } }