From e573cc7d5faf40409d0dd0201aae73f615327743 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Fri, 30 Dec 2022 13:58:02 +0900 Subject: [PATCH 1/2] Seal CommandExt trait This is technically a breaking change, but we follow the standard library's decision that sealing CommandExt is fine. https://github.com/rust-lang/rust/commit/bfd1ccfb271f03aa85488408c3b03a15ad8d7c7f --- src/lib.rs | 4 ++++ src/unix.rs | 6 +++++- src/windows.rs | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e7b3b51..ae56332 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,6 +82,10 @@ pub mod unix; #[cfg(windows)] pub mod windows; +mod sealed { + pub trait Sealed {} +} + /// An event delivered every time the SIGCHLD signal occurs. static SIGCHLD: Event = Event::new(); diff --git a/src/unix.rs b/src/unix.rs index 4208ecf..034f881 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -7,7 +7,10 @@ use std::os::unix::process::CommandExt as _; use crate::Command; /// Unix-specific extensions to the [`Command`] builder. -pub trait CommandExt { +/// +/// This trait is sealed: it cannot be implemented outside `async-process`. +/// This is so that future additional methods are not breaking changes. +pub trait CommandExt: crate::sealed::Sealed { /// Sets the child process's user ID. This translates to a /// `setuid` call in the child process. Failure in the `setuid` /// call will cause the spawn to fail. @@ -88,6 +91,7 @@ pub trait CommandExt { S: AsRef; } +impl crate::sealed::Sealed for Command {} impl CommandExt for Command { fn uid(&mut self, id: u32) -> &mut Command { self.inner.uid(id); diff --git a/src/windows.rs b/src/windows.rs index 64c042c..96f9970 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -6,7 +6,10 @@ use std::os::windows::process::CommandExt as _; use crate::{Child, Command}; /// Windows-specific extensions to the [`Command`] builder. -pub trait CommandExt { +/// +/// This trait is sealed: it cannot be implemented outside `async-process`. +/// This is so that future additional methods are not breaking changes. +pub trait CommandExt: crate::sealed::Sealed { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. @@ -15,6 +18,7 @@ pub trait CommandExt { fn creation_flags(&mut self, flags: u32) -> &mut Command; } +impl crate::sealed::Sealed for Command {} impl CommandExt for Command { fn creation_flags(&mut self, flags: u32) -> &mut Command { self.inner.creation_flags(flags); From 09ee05ec2647dea66a473efa13cc1b510cf15cd5 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Fri, 30 Dec 2022 14:23:57 +0900 Subject: [PATCH 2/2] Add windows::CommandExt::raw_arg on Rust 1.62+ --- build.rs | 3 +++ src/lib.rs | 6 ++++++ src/windows.rs | 17 +++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/build.rs b/build.rs index d5d1af7..6752846 100644 --- a/build.rs +++ b/build.rs @@ -10,6 +10,9 @@ fn main() { } }; + if !cfg.probe_rustc_version(1, 62) { + autocfg::emit("async_process_no_windows_raw_arg"); + } if !cfg.probe_rustc_version(1, 63) { autocfg::emit("async_process_no_io_safety"); } diff --git a/src/lib.rs b/src/lib.rs index ae56332..9f2bb6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -520,6 +520,7 @@ impl AsRawFd for ChildStdin { } } +/// **Note:** This implementation is only available on Rust 1.63+. #[cfg(all(not(async_process_no_io_safety), unix))] impl AsFd for ChildStdin { fn as_fd(&self) -> BorrowedFd<'_> { @@ -527,6 +528,7 @@ impl AsFd for ChildStdin { } } +/// **Note:** This implementation is only available on Rust 1.63+. #[cfg(all(not(async_process_no_io_safety), unix))] impl TryFrom for OwnedFd { type Error = io::Error; @@ -604,6 +606,7 @@ impl AsRawFd for ChildStdout { } } +/// **Note:** This implementation is only available on Rust 1.63+. #[cfg(all(not(async_process_no_io_safety), unix))] impl AsFd for ChildStdout { fn as_fd(&self) -> BorrowedFd<'_> { @@ -611,6 +614,7 @@ impl AsFd for ChildStdout { } } +/// **Note:** This implementation is only available on Rust 1.63+. #[cfg(all(not(async_process_no_io_safety), unix))] impl TryFrom for OwnedFd { type Error = io::Error; @@ -677,6 +681,7 @@ impl AsRawFd for ChildStderr { } } +/// **Note:** This implementation is only available on Rust 1.63+. #[cfg(all(not(async_process_no_io_safety), unix))] impl AsFd for ChildStderr { fn as_fd(&self) -> BorrowedFd<'_> { @@ -684,6 +689,7 @@ impl AsFd for ChildStderr { } } +/// **Note:** This implementation is only available on Rust 1.63+. #[cfg(all(not(async_process_no_io_safety), unix))] impl TryFrom for OwnedFd { type Error = io::Error; diff --git a/src/windows.rs b/src/windows.rs index 96f9970..453d3a5 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,5 +1,7 @@ //! Windows-specific extensions. +#[cfg(not(async_process_no_windows_raw_arg))] +use std::ffi::OsStr; use std::os::windows::io::{AsRawHandle, RawHandle}; use std::os::windows::process::CommandExt as _; @@ -16,6 +18,15 @@ pub trait CommandExt: crate::sealed::Sealed { /// /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags fn creation_flags(&mut self, flags: u32) -> &mut Command; + + /// Append literal text to the command line without any quoting or escaping. + /// + /// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow + /// `CommandLineToArgvW` escaping rules. + /// + /// **Note:** This method is only available on Rust 1.62+. + #[cfg(not(async_process_no_windows_raw_arg))] + fn raw_arg>(&mut self, text_to_append_as_is: S) -> &mut Command; } impl crate::sealed::Sealed for Command {} @@ -24,6 +35,12 @@ impl CommandExt for Command { self.inner.creation_flags(flags); self } + + #[cfg(not(async_process_no_windows_raw_arg))] + fn raw_arg>(&mut self, text_to_append_as_is: S) -> &mut Command { + self.inner.raw_arg(text_to_append_as_is); + self + } } impl AsRawHandle for Child {