Rollup merge of #87863 - ChrisDenton:command-env-path-fix, r=dtolnay

Fix Windows Command::env("PATH")

Fixes #87859
This commit is contained in:
Guillaume Gomez 2021-08-12 13:25:06 +02:00 committed by GitHub
commit cc54fdadd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 9 deletions

View File

@ -3,7 +3,6 @@
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use crate::borrow::Borrow;
use crate::cmp; use crate::cmp;
use crate::collections::BTreeMap; use crate::collections::BTreeMap;
use crate::convert::{TryFrom, TryInto}; use crate::convert::{TryFrom, TryInto};
@ -46,6 +45,12 @@ pub struct EnvKey {
utf16: Vec<u16>, utf16: Vec<u16>,
} }
impl EnvKey {
fn new<T: Into<OsString>>(key: T) -> Self {
EnvKey::from(key.into())
}
}
// Comparing Windows environment variable keys[1] are behaviourally the // Comparing Windows environment variable keys[1] are behaviourally the
// composition of two operations[2]: // composition of two operations[2]:
// //
@ -100,6 +105,20 @@ impl PartialEq for EnvKey {
} }
} }
} }
impl PartialOrd<str> for EnvKey {
fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
Some(self.cmp(&EnvKey::new(other)))
}
}
impl PartialEq<str> for EnvKey {
fn eq(&self, other: &str) -> bool {
if self.os_string.len() != other.len() {
false
} else {
self.cmp(&EnvKey::new(other)) == cmp::Ordering::Equal
}
}
}
// Environment variable keys should preserve their original case even though // Environment variable keys should preserve their original case even though
// they are compared using a caseless string mapping. // they are compared using a caseless string mapping.
@ -115,9 +134,9 @@ impl From<EnvKey> for OsString {
} }
} }
impl Borrow<OsStr> for EnvKey { impl From<&OsStr> for EnvKey {
fn borrow(&self) -> &OsStr { fn from(k: &OsStr) -> Self {
&self.os_string Self::from(k.to_os_string())
} }
} }
@ -242,7 +261,7 @@ impl Command {
// to read the *child's* PATH if one is provided. See #15149 for more // to read the *child's* PATH if one is provided. See #15149 for more
// details. // details.
let program = maybe_env.as_ref().and_then(|env| { let program = maybe_env.as_ref().and_then(|env| {
if let Some(v) = env.get(OsStr::new("PATH")) { if let Some(v) = env.get(&EnvKey::new("PATH")) {
// Split the value and test each path to see if the // Split the value and test each path to see if the
// program exists. // program exists.
for path in split_paths(&v) { for path in split_paths(&v) {

View File

@ -65,16 +65,18 @@ impl CommandEnv {
// The following functions build up changes // The following functions build up changes
pub fn set(&mut self, key: &OsStr, value: &OsStr) { pub fn set(&mut self, key: &OsStr, value: &OsStr) {
let key = EnvKey::from(key);
self.maybe_saw_path(&key); self.maybe_saw_path(&key);
self.vars.insert(key.to_owned().into(), Some(value.to_owned())); self.vars.insert(key, Some(value.to_owned()));
} }
pub fn remove(&mut self, key: &OsStr) { pub fn remove(&mut self, key: &OsStr) {
let key = EnvKey::from(key);
self.maybe_saw_path(&key); self.maybe_saw_path(&key);
if self.clear { if self.clear {
self.vars.remove(key); self.vars.remove(&key);
} else { } else {
self.vars.insert(key.to_owned().into(), None); self.vars.insert(key, None);
} }
} }
@ -87,7 +89,7 @@ impl CommandEnv {
self.saw_path || self.clear self.saw_path || self.clear
} }
fn maybe_saw_path(&mut self, key: &OsStr) { fn maybe_saw_path(&mut self, key: &EnvKey) {
if !self.saw_path && key == "PATH" { if !self.saw_path && key == "PATH" {
self.saw_path = true; self.saw_path = true;
} }