Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions library/std/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@
mod tests;

use crate::convert::Infallible;
use crate::ffi::OsStr;
use crate::ffi::{OsStr, OsString};
use crate::io::prelude::*;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
use crate::num::NonZero;
Expand Down Expand Up @@ -1157,7 +1157,8 @@ impl Command {
/// [`Command::env_remove`] can be retrieved with this method.
///
/// Note that this output does not include environment variables inherited from the parent
/// process.
/// process. To see the full list of environment variables, including those inherited from the
/// parent process, use [`Command::get_resolved_envs`].
///
/// Each element is a tuple key/value pair `(&OsStr, Option<&OsStr>)`. A [`None`] value
/// indicates its key was explicitly removed via [`Command::env_remove`]. The associated key for
Expand Down Expand Up @@ -1186,6 +1187,42 @@ impl Command {
CommandEnvs { iter: self.inner.get_envs() }
}

/// Returns an iterator of the environment variables that will be set when the process is spawned.
///
/// This returns the environment as it would be if the command were executed at the time of calling
/// this method. The returned environment includes:
/// - All inherited environment variables from the parent process (unless [`Command::env_clear`] was called)
/// - All environment variables explicitly set via [`Command::env`] or [`Command::envs`]
/// - Excluding any environment variables removed via [`Command::env_remove`]
///
/// Note that the returned environment is a snapshot at the time this method is called and will not
/// reflect any subsequent changes to the `Command` or the parent process's environment. Additionally,
/// it will not reflect changes made in a `pre_exec` hook (on Unix platforms).
///
/// Each element is a tuple `(OsString, OsString)` representing an environment variable key and value.
///
/// # Examples
///
/// ```
/// #![feature(command_get_resolved_envs)]
/// use std::process::Command;
/// use std::ffi::{OsString, OsStr};
/// use std::env;
/// use std::collections::HashMap;
///
/// let mut cmd = Command::new("ls");
/// cmd.env("TZ", "UTC");
/// unsafe { env::set_var("EDITOR", "vim"); }
///
/// let resolved: HashMap<OsString, OsString> = cmd.get_resolved_envs().collect();
/// assert_eq!(resolved.get(OsStr::new("TZ")), Some(&OsString::from("UTC")));
/// assert_eq!(resolved.get(OsStr::new("EDITOR")), Some(&OsString::from("vim")));
/// ```
#[unstable(feature = "command_get_resolved_envs", issue = "149070")]
pub fn get_resolved_envs(&self) -> impl Iterator<Item = (OsString, OsString)> {
self.inner.get_resolved_envs()
}

/// Returns the working directory for the child process.
///
/// This returns [`None`] if the working directory will not be changed.
Expand Down
32 changes: 32 additions & 0 deletions library/std/src/sys/process/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,35 @@ impl<'a> ExactSizeIterator for CommandEnvs<'a> {
self.iter.is_empty()
}
}

/// An iterator over the fully resolved environment variables.
///
/// This struct is returned by `Command::get_resolved_envs`.
#[derive(Debug)]
pub struct ResolvedEnvs {
inner: crate::collections::btree_map::IntoIter<EnvKey, OsString>,
}

impl ResolvedEnvs {
pub(crate) fn new(map: BTreeMap<EnvKey, OsString>) -> Self {
Self { inner: map.into_iter() }
}
}

impl Iterator for ResolvedEnvs {
type Item = (OsString, OsString);

fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|(key, value)| (key.into(), value))
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}

impl ExactSizeIterator for ResolvedEnvs {
fn len(&self) -> usize {
self.inner.len()
}
}
6 changes: 5 additions & 1 deletion library/std/src/sys/process/motor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::CommandEnvs;
use super::env::CommandEnv;
use super::env::{CommandEnv, ResolvedEnvs};
use crate::ffi::OsStr;
pub use crate::ffi::OsString as EnvKey;
use crate::num::NonZeroI32;
Expand Down Expand Up @@ -102,6 +102,10 @@ impl Command {
self.env.does_clear()
}

pub fn get_resolved_envs(&self) -> ResolvedEnvs {
ResolvedEnvs::new(self.env.capture())
}

pub fn get_current_dir(&self) -> Option<&Path> {
self.cwd.as_ref().map(Path::new)
}
Expand Down
6 changes: 5 additions & 1 deletion library/std/src/sys/process/uefi.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use r_efi::protocols::{simple_text_input, simple_text_output};

use super::env::{CommandEnv, CommandEnvs};
use super::env::{CommandEnv, CommandEnvs, ResolvedEnvs};
use crate::collections::BTreeMap;
pub use crate::ffi::OsString as EnvKey;
use crate::ffi::{OsStr, OsString};
Expand Down Expand Up @@ -87,6 +87,10 @@ impl Command {
self.env.does_clear()
}

pub fn get_resolved_envs(&self) -> ResolvedEnvs {
ResolvedEnvs::new(self.env.capture())
}

pub fn get_current_dir(&self) -> Option<&Path> {
None
}
Expand Down
6 changes: 5 additions & 1 deletion library/std/src/sys/process/unix/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,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::process::env::{CommandEnv, CommandEnvs};
use crate::sys::process::env::{CommandEnv, CommandEnvs, ResolvedEnvs};
use crate::sys_common::{FromInner, IntoInner};
use crate::{fmt, io};

Expand Down Expand Up @@ -267,6 +267,10 @@ impl Command {
self.env.does_clear()
}

pub fn get_resolved_envs(&self) -> ResolvedEnvs {
ResolvedEnvs::new(self.env.capture())
}

pub fn get_current_dir(&self) -> Option<&Path> {
self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes())))
}
Expand Down
6 changes: 5 additions & 1 deletion library/std/src/sys/process/unsupported.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::env::{CommandEnv, CommandEnvs};
use super::env::{CommandEnv, CommandEnvs, ResolvedEnvs};
pub use crate::ffi::OsString as EnvKey;
use crate::ffi::{OsStr, OsString};
use crate::num::NonZero;
Expand Down Expand Up @@ -90,6 +90,10 @@ impl Command {
self.env.does_clear()
}

pub fn get_resolved_envs(&self) -> ResolvedEnvs {
ResolvedEnvs::new(self.env.capture())
}

pub fn get_current_dir(&self) -> Option<&Path> {
self.cwd.as_ref().map(|cs| Path::new(cs))
}
Expand Down
6 changes: 5 additions & 1 deletion library/std/src/sys/process/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod tests;

use core::ffi::c_void;

use super::env::{CommandEnv, CommandEnvs};
use super::env::{CommandEnv, CommandEnvs, ResolvedEnvs};
use crate::collections::BTreeMap;
use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX};
use crate::ffi::{OsStr, OsString};
Expand Down Expand Up @@ -254,6 +254,10 @@ impl Command {
self.env.does_clear()
}

pub fn get_resolved_envs(&self) -> ResolvedEnvs {
ResolvedEnvs::new(self.env.capture())
}

pub fn get_current_dir(&self) -> Option<&Path> {
self.cwd.as_ref().map(Path::new)
}
Expand Down
Loading