From 5f145689b1c0a313ee737de296a57d1479c18cb5 Mon Sep 17 00:00:00 2001
From: joboet <jonasboettiger@icloud.com>
Date: Thu, 27 Mar 2025 14:20:25 +0100
Subject: [PATCH] std: get rid of `sys_common::process`

Move the public `CommandEnvs` into the `process` module (and make it a wrapper type for an internal iterator type) and everything else into `sys::process` as per #117276.
---
 library/std/src/process.rs                    |  48 +++++++-
 .../process.rs => sys/process/env.rs}         |  48 +-------
 library/std/src/sys/process/mod.rs            |  59 +++++++++
 library/std/src/sys/process/uefi.rs           | 116 +++++++++---------
 library/std/src/sys/process/unix/common.rs    |   2 +-
 library/std/src/sys/process/unix/fuchsia.rs   |   5 -
 library/std/src/sys/process/unix/unix.rs      |   5 -
 .../std/src/sys/process/unix/unsupported.rs   |   8 +-
 library/std/src/sys/process/unix/vxworks.rs   |   5 -
 library/std/src/sys/process/unsupported.rs    |   8 +-
 library/std/src/sys/process/windows.rs        |   7 +-
 library/std/src/sys_common/mod.rs             |   1 -
 12 files changed, 176 insertions(+), 136 deletions(-)
 rename library/std/src/{sys_common/process.rs => sys/process/env.rs} (67%)

diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 76ce7bce81b15..df6b9a6e563ce 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -168,8 +168,6 @@ use crate::num::NonZero;
 use crate::path::Path;
 use crate::sys::pipe::{AnonPipe, read2};
 use crate::sys::process as imp;
-#[stable(feature = "command_access", since = "1.57.0")]
-pub use crate::sys_common::process::CommandEnvs;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 use crate::{fmt, fs, str};
 
@@ -1073,7 +1071,7 @@ impl Command {
     /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn output(&mut self) -> io::Result<Output> {
-        let (status, stdout, stderr) = self.inner.output()?;
+        let (status, stdout, stderr) = imp::output(&mut self.inner)?;
         Ok(Output { status: ExitStatus(status), stdout, stderr })
     }
 
@@ -1174,7 +1172,7 @@ impl Command {
     /// ```
     #[stable(feature = "command_access", since = "1.57.0")]
     pub fn get_envs(&self) -> CommandEnvs<'_> {
-        self.inner.get_envs()
+        CommandEnvs { iter: self.inner.get_envs() }
     }
 
     /// Returns the working directory for the child process.
@@ -1264,6 +1262,48 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> {
     }
 }
 
+/// An iterator over the command environment variables.
+///
+/// This struct is created by
+/// [`Command::get_envs`][crate::process::Command::get_envs]. See its
+/// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
+#[stable(feature = "command_access", since = "1.57.0")]
+pub struct CommandEnvs<'a> {
+    iter: imp::CommandEnvs<'a>,
+}
+
+#[stable(feature = "command_access", since = "1.57.0")]
+impl<'a> Iterator for CommandEnvs<'a> {
+    type Item = (&'a OsStr, Option<&'a OsStr>);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.iter.next()
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+#[stable(feature = "command_access", since = "1.57.0")]
+impl<'a> ExactSizeIterator for CommandEnvs<'a> {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
+
+#[stable(feature = "command_access", since = "1.57.0")]
+impl<'a> fmt::Debug for CommandEnvs<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.iter.fmt(f)
+    }
+}
+
 /// The output of a finished process.
 ///
 /// This is returned in a Result by either the [`output`] method of a
diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys/process/env.rs
similarity index 67%
rename from library/std/src/sys_common/process.rs
rename to library/std/src/sys/process/env.rs
index 9f61d69d85875..e08b476540ef9 100644
--- a/library/std/src/sys_common/process.rs
+++ b/library/std/src/sys/process/env.rs
@@ -1,13 +1,9 @@
-#![allow(dead_code)]
-#![unstable(feature = "process_internals", issue = "none")]
-
 use crate::collections::BTreeMap;
 use crate::ffi::{OsStr, OsString};
-use crate::sys::pipe::read2;
-use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};
-use crate::{env, fmt, io};
+use crate::sys::process::EnvKey;
+use crate::{env, fmt};
 
-// Stores a set of changes to an environment
+/// Stores a set of changes to an environment
 #[derive(Clone, Default)]
 pub struct CommandEnv {
     clear: bool,
@@ -92,30 +88,23 @@ impl CommandEnv {
     }
 }
 
-/// An iterator over the command environment variables.
-///
-/// This struct is created by
-/// [`Command::get_envs`][crate::process::Command::get_envs]. See its
-/// documentation for more.
-#[must_use = "iterators are lazy and do nothing unless consumed"]
-#[stable(feature = "command_access", since = "1.57.0")]
 #[derive(Debug)]
 pub struct CommandEnvs<'a> {
     iter: crate::collections::btree_map::Iter<'a, EnvKey, Option<OsString>>,
 }
 
-#[stable(feature = "command_access", since = "1.57.0")]
 impl<'a> Iterator for CommandEnvs<'a> {
     type Item = (&'a OsStr, Option<&'a OsStr>);
+
     fn next(&mut self) -> Option<Self::Item> {
         self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref()))
     }
+
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.iter.size_hint()
     }
 }
 
-#[stable(feature = "command_access", since = "1.57.0")]
 impl<'a> ExactSizeIterator for CommandEnvs<'a> {
     fn len(&self) -> usize {
         self.iter.len()
@@ -124,30 +113,3 @@ impl<'a> ExactSizeIterator for CommandEnvs<'a> {
         self.iter.is_empty()
     }
 }
-
-pub fn wait_with_output(
-    mut process: Process,
-    mut pipes: StdioPipes,
-) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-    drop(pipes.stdin.take());
-
-    let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
-    match (pipes.stdout.take(), pipes.stderr.take()) {
-        (None, None) => {}
-        (Some(out), None) => {
-            let res = out.read_to_end(&mut stdout);
-            res.unwrap();
-        }
-        (None, Some(err)) => {
-            let res = err.read_to_end(&mut stderr);
-            res.unwrap();
-        }
-        (Some(out), Some(err)) => {
-            let res = read2(out, &mut stdout, err, &mut stderr);
-            res.unwrap();
-        }
-    }
-
-    let status = process.wait()?;
-    Ok((status, stdout, stderr))
-}
diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs
index 92cfac7f47cf6..91c7005a32855 100644
--- a/library/std/src/sys/process/mod.rs
+++ b/library/std/src/sys/process/mod.rs
@@ -14,6 +14,65 @@ cfg_if::cfg_if! {
     }
 }
 
+// This module is shared by all platforms, but nearly all platforms except for
+// the "normal" UNIX ones leave some of this code unused.
+#[cfg_attr(not(target_os = "linux"), allow(dead_code))]
+mod env;
+
+pub use env::CommandEnvs;
 pub use imp::{
     Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, StdioPipes,
 };
+
+#[cfg(any(
+    all(
+        target_family = "unix",
+        not(any(
+            target_os = "espidf",
+            target_os = "horizon",
+            target_os = "vita",
+            target_os = "nuttx"
+        ))
+    ),
+    target_os = "windows",
+))]
+pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+    use crate::sys::pipe::read2;
+
+    let (mut process, mut pipes) = cmd.spawn(Stdio::MakePipe, false)?;
+
+    drop(pipes.stdin.take());
+    let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
+    match (pipes.stdout.take(), pipes.stderr.take()) {
+        (None, None) => {}
+        (Some(out), None) => {
+            let res = out.read_to_end(&mut stdout);
+            res.unwrap();
+        }
+        (None, Some(err)) => {
+            let res = err.read_to_end(&mut stderr);
+            res.unwrap();
+        }
+        (Some(out), Some(err)) => {
+            let res = read2(out, &mut stdout, err, &mut stderr);
+            res.unwrap();
+        }
+    }
+
+    let status = process.wait()?;
+    Ok((status, stdout, stderr))
+}
+
+#[cfg(not(any(
+    all(
+        target_family = "unix",
+        not(any(
+            target_os = "espidf",
+            target_os = "horizon",
+            target_os = "vita",
+            target_os = "nuttx"
+        ))
+    ),
+    target_os = "windows",
+)))]
+pub use imp::output;
diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs
index 5f922292d0542..4864c58698817 100644
--- a/library/std/src/sys/process/uefi.rs
+++ b/library/std/src/sys/process/uefi.rs
@@ -1,5 +1,6 @@
 use r_efi::protocols::{simple_text_input, simple_text_output};
 
+use super::env::{CommandEnv, CommandEnvs};
 use crate::collections::BTreeMap;
 pub use crate::ffi::OsString as EnvKey;
 use crate::ffi::{OsStr, OsString};
@@ -10,7 +11,6 @@ use crate::sys::pal::helpers;
 use crate::sys::pal::os::error_string;
 use crate::sys::pipe::AnonPipe;
 use crate::sys::unsupported;
-use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::{fmt, io};
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -139,72 +139,72 @@ impl Command {
             Stdio::MakePipe => unsupported(),
         }
     }
+}
 
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
-
-        // UEFI adds the bin name by default
-        if !self.args.is_empty() {
-            let args = uefi_command_internal::create_args(&self.prog, &self.args);
-            cmd.set_args(args);
-        }
-
-        // Setup Stdout
-        let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
-        let stdout = Self::create_pipe(stdout)?;
-        if let Some(con) = stdout {
-            cmd.stdout_init(con)
-        } else {
-            cmd.stdout_inherit()
-        };
-
-        // Setup Stderr
-        let stderr = self.stderr.unwrap_or(Stdio::MakePipe);
-        let stderr = Self::create_pipe(stderr)?;
-        if let Some(con) = stderr {
-            cmd.stderr_init(con)
-        } else {
-            cmd.stderr_inherit()
-        };
-
-        // Setup Stdin
-        let stdin = self.stdin.unwrap_or(Stdio::Null);
-        let stdin = Self::create_stdin(stdin)?;
-        if let Some(con) = stdin {
-            cmd.stdin_init(con)
-        } else {
-            cmd.stdin_inherit()
-        };
-
-        let env = env_changes(&self.env);
-
-        // Set any new vars
-        if let Some(e) = &env {
-            for (k, (_, v)) in e {
-                match v {
-                    Some(v) => unsafe { crate::env::set_var(k, v) },
-                    None => unsafe { crate::env::remove_var(k) },
-                }
+pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+    let mut cmd = uefi_command_internal::Image::load_image(&command.prog)?;
+
+    // UEFI adds the bin name by default
+    if !command.args.is_empty() {
+        let args = uefi_command_internal::create_args(&command.prog, &command.args);
+        cmd.set_args(args);
+    }
+
+    // Setup Stdout
+    let stdout = command.stdout.unwrap_or(Stdio::MakePipe);
+    let stdout = Command::create_pipe(stdout)?;
+    if let Some(con) = stdout {
+        cmd.stdout_init(con)
+    } else {
+        cmd.stdout_inherit()
+    };
+
+    // Setup Stderr
+    let stderr = command.stderr.unwrap_or(Stdio::MakePipe);
+    let stderr = Command::create_pipe(stderr)?;
+    if let Some(con) = stderr {
+        cmd.stderr_init(con)
+    } else {
+        cmd.stderr_inherit()
+    };
+
+    // Setup Stdin
+    let stdin = command.stdin.unwrap_or(Stdio::Null);
+    let stdin = Command::create_stdin(stdin)?;
+    if let Some(con) = stdin {
+        cmd.stdin_init(con)
+    } else {
+        cmd.stdin_inherit()
+    };
+
+    let env = env_changes(&command.env);
+
+    // Set any new vars
+    if let Some(e) = &env {
+        for (k, (_, v)) in e {
+            match v {
+                Some(v) => unsafe { crate::env::set_var(k, v) },
+                None => unsafe { crate::env::remove_var(k) },
             }
         }
+    }
 
-        let stat = cmd.start_image()?;
+    let stat = cmd.start_image()?;
 
-        // Rollback any env changes
-        if let Some(e) = env {
-            for (k, (v, _)) in e {
-                match v {
-                    Some(v) => unsafe { crate::env::set_var(k, v) },
-                    None => unsafe { crate::env::remove_var(k) },
-                }
+    // Rollback any env changes
+    if let Some(e) = env {
+        for (k, (v, _)) in e {
+            match v {
+                Some(v) => unsafe { crate::env::set_var(k, v) },
+                None => unsafe { crate::env::remove_var(k) },
             }
         }
+    }
 
-        let stdout = cmd.stdout()?;
-        let stderr = cmd.stderr()?;
+    let stdout = cmd.stdout()?;
+    let stderr = cmd.stderr()?;
 
-        Ok((ExitStatus(stat), stdout, stderr))
-    }
+    Ok((ExitStatus(stat), stdout, stderr))
 }
 
 impl From<AnonPipe> for Stdio {
diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs
index 8bc17f314911d..a9c2510e6d454 100644
--- a/library/std/src/sys/process/unix/common.rs
+++ b/library/std/src/sys/process/unix/common.rs
@@ -12,7 +12,7 @@ use crate::sys::fs::File;
 #[cfg(not(target_os = "fuchsia"))]
 use crate::sys::fs::OpenOptions;
 use crate::sys::pipe::{self, AnonPipe};
-use crate::sys_common::process::{CommandEnv, CommandEnvs};
+use crate::sys::process::env::{CommandEnv, CommandEnvs};
 use crate::sys_common::{FromInner, IntoInner};
 use crate::{fmt, io, ptr};
 
diff --git a/library/std/src/sys/process/unix/fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs
index 0de32ecffd4b0..fbe06c4799be5 100644
--- a/library/std/src/sys/process/unix/fuchsia.rs
+++ b/library/std/src/sys/process/unix/fuchsia.rs
@@ -31,11 +31,6 @@ impl Command {
         Ok((Process { handle: Handle::new(process_handle) }, ours))
     }
 
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
-        crate::sys_common::process::wait_with_output(proc, pipes)
-    }
-
     pub fn exec(&mut self, default: Stdio) -> io::Error {
         if self.saw_nul() {
             return io::const_error!(
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index ae1c9558281eb..1b3bd2de265da 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -162,11 +162,6 @@ impl Command {
         }
     }
 
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
-        crate::sys_common::process::wait_with_output(proc, pipes)
-    }
-
     // WatchOS and TVOS headers mark the `fork`/`exec*` functions with
     // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, and indicate that the
     // `posix_spawn*` functions should be used instead. It isn't entirely clear
diff --git a/library/std/src/sys/process/unix/unsupported.rs b/library/std/src/sys/process/unix/unsupported.rs
index 78d270923cfa2..e86561a5c5c4f 100644
--- a/library/std/src/sys/process/unix/unsupported.rs
+++ b/library/std/src/sys/process/unix/unsupported.rs
@@ -18,15 +18,15 @@ impl Command {
         unsupported()
     }
 
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        unsupported()
-    }
-
     pub fn exec(&mut self, _default: Stdio) -> io::Error {
         unsupported_err()
     }
 }
 
+pub fn output(_: &mut Command) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+    unsupported()
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Processes
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs
index b92446f0cf673..fab3b36ebf3fa 100644
--- a/library/std/src/sys/process/unix/vxworks.rs
+++ b/library/std/src/sys/process/unix/vxworks.rs
@@ -112,11 +112,6 @@ impl Command {
         }
     }
 
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
-        crate::sys_common::process::wait_with_output(proc, pipes)
-    }
-
     pub fn exec(&mut self, default: Stdio) -> io::Error {
         let ret = Command::spawn(self, default, false);
         match ret {
diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs
index fee81744f09ec..469922c78aca2 100644
--- a/library/std/src/sys/process/unsupported.rs
+++ b/library/std/src/sys/process/unsupported.rs
@@ -1,3 +1,4 @@
+use super::env::{CommandEnv, CommandEnvs};
 pub use crate::ffi::OsString as EnvKey;
 use crate::ffi::{OsStr, OsString};
 use crate::num::NonZero;
@@ -5,7 +6,6 @@ use crate::path::Path;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
 use crate::sys::unsupported;
-use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::{fmt, io};
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -104,10 +104,10 @@ impl Command {
     ) -> io::Result<(Process, StdioPipes)> {
         unsupported()
     }
+}
 
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        unsupported()
-    }
+pub fn output(_cmd: &mut Command) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+    unsupported()
 }
 
 impl From<AnonPipe> for Stdio {
diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs
index 4cfdf908c58de..4acd753eec915 100644
--- a/library/std/src/sys/process/windows.rs
+++ b/library/std/src/sys/process/windows.rs
@@ -5,6 +5,7 @@ mod tests;
 
 use core::ffi::c_void;
 
+use super::env::{CommandEnv, CommandEnvs};
 use crate::collections::BTreeMap;
 use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX};
 use crate::ffi::{OsStr, OsString};
@@ -24,7 +25,6 @@ use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf};
 use crate::sys::pipe::{self, AnonPipe};
 use crate::sys::{cvt, path, stdio};
 use crate::sys_common::IntoInner;
-use crate::sys_common::process::{CommandEnv, CommandEnvs};
 use crate::{cmp, env, fmt, ptr};
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -389,11 +389,6 @@ impl Command {
             ))
         }
     }
-
-    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
-        let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
-        crate::sys_common::process::wait_with_output(proc, pipes)
-    }
 }
 
 impl fmt::Debug for Command {
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 2a5de7f66661c..b7f4656fa3701 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -20,7 +20,6 @@
 #[cfg(test)]
 mod tests;
 
-pub mod process;
 pub mod wstr;
 pub mod wtf8;