diff --git a/crates/uv-trampoline/src/bounce.rs b/crates/uv-trampoline/src/bounce.rs index be83fcf3b..30186997a 100644 --- a/crates/uv-trampoline/src/bounce.rs +++ b/crates/uv-trampoline/src/bounce.rs @@ -32,7 +32,7 @@ use windows::Win32::{ }, }; -use crate::{eprintln, format}; +use crate::{error, format, warn}; const PATH_LEN_SIZE: usize = size_of::(); const MAX_PATH_LEN: u32 = 32 * 1024; @@ -68,8 +68,7 @@ impl TrampolineKind { /// depending on the [`TrampolineKind`]. fn make_child_cmdline() -> CString { let executable_name = std::env::current_exe().unwrap_or_else(|_| { - eprintln!("Failed to get executable name"); - exit_with_status(1); + error_and_exit("Failed to get executable name"); }); let (kind, python_exe) = read_trampoline_metadata(executable_name.as_ref()); let mut child_cmdline = Vec::::new(); @@ -94,15 +93,14 @@ fn make_child_cmdline() -> CString { child_cmdline.push(b'\0'); // Helpful when debugging trampoline issues - // eprintln!( + // warn!( // "executable_name: '{}'\nnew_cmdline: {}", // &*executable_name.to_string_lossy(), // std::str::from_utf8(child_cmdline.as_slice()).unwrap() // ); CString::from_vec_with_nul(child_cmdline).unwrap_or_else(|_| { - eprintln!("Child command line is not correctly null terminated"); - exit_with_status(1); + error_and_exit("Child command line is not correctly null terminated"); }) } @@ -175,8 +173,7 @@ fn read_trampoline_metadata(executable_name: &Path) -> (TrampolineKind, PathBuf) buffer.truncate(read_bytes); let Some(inner_kind) = TrampolineKind::from_buffer(&buffer) else { - eprintln!("Magic number 'UVSC' or 'UVPY' not found at the end of the file. Did you append the magic number, the length and the path to the python executable at the end of the file?"); - exit_with_status(1); + error_and_exit("Magic number 'UVSC' or 'UVPY' not found at the end of the file. Did you append the magic number, the length and the path to the python executable at the end of the file?"); }; kind = inner_kind; @@ -186,21 +183,18 @@ fn read_trampoline_metadata(executable_name: &Path) -> (TrampolineKind, PathBuf) let path_len = match buffer.get(buffer.len() - PATH_LEN_SIZE..) { Some(path_len) => { let path_len = u32::from_le_bytes(path_len.try_into().unwrap_or_else(|_| { - eprintln!("Slice length is not equal to 4 bytes"); - exit_with_status(1); + error_and_exit("Slice length is not equal to 4 bytes"); })); if path_len > MAX_PATH_LEN { - eprintln!("Only paths with a length up to 32KBs are supported but the python path has a length of {}", path_len); - exit_with_status(1); + error_and_exit(&format!("Only paths with a length up to 32KBs are supported but the python path has a length of {}", path_len)); } // SAFETY: path len is guaranteed to be less than 32KBs path_len as usize } None => { - eprintln!("Python executable length missing. Did you write the length of the path to the Python executable before the Magic number?"); - exit_with_status(1); + error_and_exit("Python executable length missing. Did you write the length of the path to the Python executable before the Magic number?"); } }; @@ -211,8 +205,7 @@ fn read_trampoline_metadata(executable_name: &Path) -> (TrampolineKind, PathBuf) buffer.drain(..path_offset); break String::from_utf8(buffer).unwrap_or_else(|_| { - eprintln!("Python executable path is not a valid UTF-8 encoded path"); - exit_with_status(1); + error_and_exit("Python executable path is not a valid UTF-8 encoded path"); }); } else { // SAFETY: Casting to u32 is safe because `path_len` is guaranteed to be less than 32KBs, @@ -220,8 +213,7 @@ fn read_trampoline_metadata(executable_name: &Path) -> (TrampolineKind, PathBuf) bytes_to_read = (path_len + kind.magic_number().len() + PATH_LEN_SIZE) as u32; if u64::from(bytes_to_read) > file_size { - eprintln!("The length of the python executable path exceeds the file size. Verify that the path length is appended to the end of the launcher script as a u32 in little endian"); - exit_with_status(1); + error_and_exit("The length of the python executable path exceeds the file size. Verify that the path length is appended to the end of the launcher script as a u32 in little endian"); } } }; @@ -233,8 +225,7 @@ fn read_trampoline_metadata(executable_name: &Path) -> (TrampolineKind, PathBuf) let parent_dir = match executable_name.parent() { Some(parent) => parent, None => { - eprintln!("Executable path has no parent directory"); - exit_with_status(1); + error_and_exit("Executable path has no parent directory"); } }; parent_dir.join(path) @@ -242,8 +233,7 @@ fn read_trampoline_metadata(executable_name: &Path) -> (TrampolineKind, PathBuf) // NOTICE: dunce adds 5kb~ let path = dunce::canonicalize(path.as_path()).unwrap_or_else(|_| { - eprintln!("Failed to canonicalize script path"); - exit_with_status(1); + error_and_exit("Failed to canonicalize script path"); }); (kind, path) @@ -331,11 +321,11 @@ fn spawn_child(si: &STARTUPINFOA, child_cmdline: CString) -> HANDLE { if (si.dwFlags & STARTF_USESTDHANDLES).0 != 0 { // ignore errors, if the handles are not inheritable/valid, then nothing we can do unsafe { SetHandleInformation(si.hStdInput, HANDLE_FLAG_INHERIT.0, HANDLE_FLAG_INHERIT) } - .unwrap_or_else(|_| eprintln!("Making stdin inheritable failed")); + .unwrap_or_else(|_| warn!("Making stdin inheritable failed")); unsafe { SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT.0, HANDLE_FLAG_INHERIT) } - .unwrap_or_else(|_| eprintln!("Making stdout inheritable failed")); + .unwrap_or_else(|_| warn!("Making stdout inheritable failed")); unsafe { SetHandleInformation(si.hStdError, HANDLE_FLAG_INHERIT.0, HANDLE_FLAG_INHERIT) } - .unwrap_or_else(|_| eprintln!("Making stderr inheritable failed")); + .unwrap_or_else(|_| warn!("Making stderr inheritable failed")); } let mut child_process_info = PROCESS_INFORMATION::default(); unsafe { @@ -370,14 +360,14 @@ fn spawn_child(si: &STARTUPINFOA, child_cmdline: CString) -> HANDLE { // https://github.com/huangqinjin/ucrt/blob/10.0.19041.0/lowio/ioinit.cpp#L190-L223 fn close_handles(si: &STARTUPINFOA) { // See distlib/PC/launcher.c::cleanup_standard_io() - // Unlike cleanup_standard_io(), we don't close STD_ERROR_HANDLE to retain eprintln! + // Unlike cleanup_standard_io(), we don't close STD_ERROR_HANDLE to retain warn! for std_handle in [STD_INPUT_HANDLE, STD_OUTPUT_HANDLE] { if let Ok(handle) = unsafe { GetStdHandle(std_handle) } { unsafe { CloseHandle(handle) }.unwrap_or_else(|_| { - eprintln!("Failed to close standard device handle {}", handle.0 as u32); + warn!("Failed to close standard device handle {}", handle.0 as u32); }); unsafe { SetStdHandle(std_handle, INVALID_HANDLE_VALUE) }.unwrap_or_else(|_| { - eprintln!("Failed to modify standard device handle {}", std_handle.0); + warn!("Failed to modify standard device handle {}", std_handle.0); }); } } @@ -401,7 +391,7 @@ fn close_handles(si: &STARTUPINFOA) { continue; } unsafe { CloseHandle(handle) }.unwrap_or_else(|_| { - eprintln!("Failed to close child file descriptors at {}", i); + warn!("Failed to close child file descriptors at {}", i); }); } } @@ -430,14 +420,14 @@ fn clear_app_starting_state(child_handle: HANDLE) { unsafe { // End the launcher's "app starting" cursor state. PostMessageA(None, 0, WPARAM(0), LPARAM(0)).unwrap_or_else(|_| { - eprintln!("Failed to post a message to specified window"); + warn!("Failed to post a message to specified window"); }); if GetMessageA(&mut msg, None, 0, 0) != TRUE { - eprintln!("Failed to retrieve posted window message"); + warn!("Failed to retrieve posted window message"); } // Proxy the child's input idle event. if WaitForInputIdle(child_handle, INFINITE) != 0 { - eprintln!("Failed to wait for input from window"); + warn!("Failed to wait for input from window"); } // Signal the process input idle event by creating a window and pumping // sent messages. The window class isn't important, so just use the @@ -484,7 +474,7 @@ pub fn bounce(is_gui: bool) -> ! { // (best effort) Switch to some innocuous directory, so we don't hold the original cwd open. // See distlib/PC/launcher.c::switch_working_directory if std::env::set_current_dir(std::env::temp_dir()).is_err() { - eprintln!("Failed to set cwd to temp dir"); + warn!("Failed to set cwd to temp dir"); } // We want to ignore control-C/control-Break/logout/etc.; the same event will @@ -509,6 +499,12 @@ pub fn bounce(is_gui: bool) -> ! { exit_with_status(exit_code); } +#[cold] +fn error_and_exit(message: &str) -> ! { + error!("{}", message); + exit_with_status(1); +} + #[cold] fn print_last_error_and_exit(message: &str) -> ! { let err = std::io::Error::last_os_error(); @@ -518,13 +514,13 @@ fn print_last_error_and_exit(message: &str) -> ! { .unwrap_or_default(); // we can't access sys::os::error_string directly so err.kind().to_string() // is the closest we can get to while avoiding bringing in a large chunk of core::fmt - eprintln!( + let message = format!( "(uv internal error) {}: {}.{}", message, err.kind().to_string(), err_no_str ); - exit_with_status(1); + error_and_exit(&message); } #[cold] diff --git a/crates/uv-trampoline/src/diagnostics.rs b/crates/uv-trampoline/src/diagnostics.rs index 293cd03f5..514bb4e35 100644 --- a/crates/uv-trampoline/src/diagnostics.rs +++ b/crates/uv-trampoline/src/diagnostics.rs @@ -9,9 +9,16 @@ use windows::core::PCSTR; use windows::Win32::UI::WindowsAndMessaging::{MessageBoxA, MESSAGEBOX_STYLE}; #[macro_export] -macro_rules! eprintln { +macro_rules! error { ($($tt:tt)*) => {{ - $crate::diagnostics::write_diagnostic(&$crate::format!($($tt)*)); + $crate::diagnostics::write_diagnostic(&$crate::format!($($tt)*), true); + }} +} + +#[macro_export] +macro_rules! warn { + ($($tt:tt)*) => {{ + $crate::diagnostics::write_diagnostic(&$crate::format!($($tt)*), false); }} } @@ -37,11 +44,11 @@ impl uWrite for StringBuffer { } #[cold] -pub(crate) fn write_diagnostic(message: &str) { +pub(crate) fn write_diagnostic(message: &str, is_error: bool) { let mut stderr = std::io::stderr(); if !stderr.as_raw_handle().is_null() { let _ = stderr.write_all(message.as_bytes()); - } else { + } else if is_error { let nul_terminated = unsafe { CString::new(message.as_bytes()).unwrap_unchecked() }; let pcstr_message = PCSTR::from_raw(nul_terminated.as_ptr() as *const _); unsafe { MessageBoxA(None, pcstr_message, None, MESSAGEBOX_STYLE(0)) }; diff --git a/crates/uv-trampoline/trampolines/uv-trampoline-aarch64-console.exe b/crates/uv-trampoline/trampolines/uv-trampoline-aarch64-console.exe index 3b2ed57ec..3b7f76564 100755 Binary files a/crates/uv-trampoline/trampolines/uv-trampoline-aarch64-console.exe and b/crates/uv-trampoline/trampolines/uv-trampoline-aarch64-console.exe differ diff --git a/crates/uv-trampoline/trampolines/uv-trampoline-aarch64-gui.exe b/crates/uv-trampoline/trampolines/uv-trampoline-aarch64-gui.exe index a3fb2be6c..74080d4db 100755 Binary files a/crates/uv-trampoline/trampolines/uv-trampoline-aarch64-gui.exe and b/crates/uv-trampoline/trampolines/uv-trampoline-aarch64-gui.exe differ diff --git a/crates/uv-trampoline/trampolines/uv-trampoline-i686-console.exe b/crates/uv-trampoline/trampolines/uv-trampoline-i686-console.exe index 4d8b35a43..3fd1e0aff 100755 Binary files a/crates/uv-trampoline/trampolines/uv-trampoline-i686-console.exe and b/crates/uv-trampoline/trampolines/uv-trampoline-i686-console.exe differ diff --git a/crates/uv-trampoline/trampolines/uv-trampoline-i686-gui.exe b/crates/uv-trampoline/trampolines/uv-trampoline-i686-gui.exe index 972267ffb..4221696a1 100755 Binary files a/crates/uv-trampoline/trampolines/uv-trampoline-i686-gui.exe and b/crates/uv-trampoline/trampolines/uv-trampoline-i686-gui.exe differ diff --git a/crates/uv-trampoline/trampolines/uv-trampoline-x86_64-console.exe b/crates/uv-trampoline/trampolines/uv-trampoline-x86_64-console.exe index 57ecee75a..5b8fa6acc 100755 Binary files a/crates/uv-trampoline/trampolines/uv-trampoline-x86_64-console.exe and b/crates/uv-trampoline/trampolines/uv-trampoline-x86_64-console.exe differ diff --git a/crates/uv-trampoline/trampolines/uv-trampoline-x86_64-gui.exe b/crates/uv-trampoline/trampolines/uv-trampoline-x86_64-gui.exe index 919eed138..8cb19cf8f 100755 Binary files a/crates/uv-trampoline/trampolines/uv-trampoline-x86_64-gui.exe and b/crates/uv-trampoline/trampolines/uv-trampoline-x86_64-gui.exe differ