Skip to content

Commit b864262

Browse files
committed
store OsString instead of String in config.env
1 parent a148cd4 commit b864262

File tree

4 files changed

+53
-43
lines changed

4 files changed

+53
-43
lines changed

src/cargo/ops/cargo_config.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ fn maybe_env<'config>(
9393
config: &'config Config,
9494
key: &ConfigKey,
9595
cv: &CV,
96-
) -> Option<Vec<(&'config String, &'config String)>> {
96+
) -> Option<Vec<(&'config str, &'config str)>> {
9797
// Only fetching a table is unable to load env values. Leaf entries should
9898
// work properly.
9999
match cv {
@@ -102,7 +102,6 @@ fn maybe_env<'config>(
102102
}
103103
let mut env: Vec<_> = config
104104
.env()
105-
.iter()
106105
.filter(|(env_key, _val)| env_key.starts_with(&format!("{}_", key.as_env_key())))
107106
.collect();
108107
env.sort_by_key(|x| x.0);
@@ -162,7 +161,7 @@ fn print_toml(config: &Config, opts: &GetOptions<'_>, key: &ConfigKey, cv: &CV)
162161
}
163162
}
164163

165-
fn print_toml_env(config: &Config, env: &[(&String, &String)]) {
164+
fn print_toml_env(config: &Config, env: &[(&str, &str)]) {
166165
drop_println!(
167166
config,
168167
"# The following environment variables may affect the loaded values."
@@ -173,7 +172,7 @@ fn print_toml_env(config: &Config, env: &[(&String, &String)]) {
173172
}
174173
}
175174

176-
fn print_json_env(config: &Config, env: &[(&String, &String)]) {
175+
fn print_json_env(config: &Config, env: &[(&str, &str)]) {
177176
drop_eprintln!(
178177
config,
179178
"note: The following environment variables may affect the loaded values."
@@ -287,7 +286,6 @@ fn print_toml_unmerged(config: &Config, opts: &GetOptions<'_>, key: &ConfigKey)
287286
// special, and will just naturally get loaded as part of the config.
288287
let mut env: Vec<_> = config
289288
.env()
290-
.iter()
291289
.filter(|(env_key, _val)| env_key.starts_with(key.as_env_key()))
292290
.collect();
293291
if !env.is_empty() {

src/cargo/util/auth.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ pub fn registry_credential_config(
182182
let index = sid.canonical_url();
183183
let mut names: Vec<_> = config
184184
.env()
185-
.iter()
186185
.filter_map(|(k, v)| {
187186
Some((
188187
k.strip_prefix("CARGO_REGISTRIES_")?

src/cargo/util/config/de.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl<'config> ConfigMapAccess<'config> {
215215
if de.config.cli_unstable().advanced_env {
216216
// `CARGO_PROFILE_DEV_PACKAGE_`
217217
let env_prefix = format!("{}_", de.key.as_env_key());
218-
for env_key in de.config.env.keys() {
218+
for env_key in de.config.env_keys() {
219219
if env_key.starts_with(&env_prefix) {
220220
// `CARGO_PROFILE_DEV_PACKAGE_bar_OPT_LEVEL = 3`
221221
let rest = &env_key[env_prefix.len()..];
@@ -265,7 +265,7 @@ impl<'config> ConfigMapAccess<'config> {
265265
for field in given_fields {
266266
let mut field_key = de.key.clone();
267267
field_key.push(field);
268-
for env_key in de.config.env.keys() {
268+
for env_key in de.config.env_keys() {
269269
if env_key.starts_with(field_key.as_env_key()) {
270270
fields.insert(KeyKind::Normal(field.to_string()));
271271
}
@@ -424,7 +424,7 @@ impl<'config> ValueDeserializer<'config> {
424424
let definition = {
425425
let env = de.key.as_env_key();
426426
let env_def = Definition::Environment(env.to_string());
427-
match (de.config.env.contains_key(env), de.config.get_cv(&de.key)?) {
427+
match (de.config.env_has_key(env), de.config.get_cv(&de.key)?) {
428428
(true, Some(cv)) => {
429429
// Both, pick highest priority.
430430
if env_def.is_higher_priority(cv.definition()) {

src/cargo/util/config/mod.rs

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use std::cell::{RefCell, RefMut};
5454
use std::collections::hash_map::Entry::{Occupied, Vacant};
5555
use std::collections::{HashMap, HashSet};
5656
use std::env;
57-
use std::ffi::OsStr;
57+
use std::ffi::{OsStr, OsString};
5858
use std::fmt;
5959
use std::fs::{self, File};
6060
use std::io::prelude::*;
@@ -200,7 +200,7 @@ pub struct Config {
200200
/// Target Directory via resolved Cli parameter
201201
target_dir: Option<Filesystem>,
202202
/// Environment variables, separated to assist testing.
203-
env: HashMap<String, String>,
203+
env: HashMap<OsString, OsString>,
204204
/// Environment variables, converted to uppercase to check for case mismatch
205205
upper_case_env: HashMap<String, String>,
206206
/// Tracks which sources have been updated to avoid multiple updates.
@@ -260,23 +260,16 @@ impl Config {
260260
}
261261
});
262262

263-
let env: HashMap<_, _> = env::vars_os()
264-
.filter_map(|(k, v)| {
265-
// Ignore any key/values that are not valid Unicode.
266-
match (k.into_string(), v.into_string()) {
267-
(Ok(k), Ok(v)) => Some((k, v)),
268-
_ => None,
269-
}
270-
})
271-
.collect();
263+
let env: HashMap<_, _> = env::vars_os().collect();
272264

273265
let upper_case_env = env
274-
.clone()
275-
.into_iter()
276-
.map(|(k, _)| (k.to_uppercase().replace("-", "_"), k))
266+
.iter()
267+
.filter_map(|(k, _)| k.to_str()) // Only keep valid UTF-8
268+
.map(|k| (k.to_uppercase().replace("-", "_"), k.to_owned()))
277269
.collect();
278270

279-
let cache_rustc_info = match env.get("CARGO_CACHE_RUSTC_INFO") {
271+
let cache_key: &OsStr = "CARGO_CACHE_RUSTC_INFO".as_ref();
272+
let cache_rustc_info = match env.get(cache_key) {
280273
Some(cache) => cache != "0",
281274
_ => true,
282275
};
@@ -566,7 +559,7 @@ impl Config {
566559
pub fn target_dir(&self) -> CargoResult<Option<Filesystem>> {
567560
if let Some(dir) = &self.target_dir {
568561
Ok(Some(dir.clone()))
569-
} else if let Some(dir) = self.env.get("CARGO_TARGET_DIR") {
562+
} else if let Some(dir) = self.get_env_os("CARGO_TARGET_DIR") {
570563
// Check if the CARGO_TARGET_DIR environment variable is set to an empty string.
571564
if dir.is_empty() {
572565
bail!(
@@ -664,7 +657,7 @@ impl Config {
664657
// Root table can't have env value.
665658
return Ok(cv);
666659
}
667-
let env = self.env.get(key.as_env_key());
660+
let env = self.get_env_str(key.as_env_key());
668661
let env_def = Definition::Environment(key.as_env_key().to_string());
669662
let use_env = match (&cv, env) {
670663
// Lists are always merged.
@@ -735,20 +728,28 @@ impl Config {
735728

736729
/// Helper primarily for testing.
737730
pub fn set_env(&mut self, env: HashMap<String, String>) {
738-
self.env = env;
731+
self.env = env.into_iter().map(|(k, v)| (k.into(), v.into())).collect();
739732
}
740733

741-
/// Returns all environment variables.
742-
pub(crate) fn env(&self) -> &HashMap<String, String> {
743-
&self.env
734+
/// Returns all environment variables as an iterator, filtering out entries
735+
/// that are not valid UTF-8.
736+
pub(crate) fn env(&self) -> impl Iterator<Item = (&str, &str)> {
737+
self.env
738+
.iter()
739+
.filter_map(|(k, v)| Some((k.to_str()?, v.to_str()?)))
740+
}
741+
742+
/// Returns all environment variable keys, filtering out entries that are not valid UTF-8.
743+
fn env_keys(&self) -> impl Iterator<Item = &str> {
744+
self.env.iter().filter_map(|(k, _)| k.to_str())
744745
}
745746

746747
fn get_config_env<T>(&self, key: &ConfigKey) -> Result<OptValue<T>, ConfigError>
747748
where
748749
T: FromStr,
749750
<T as FromStr>::Err: fmt::Display,
750751
{
751-
match self.env.get(key.as_env_key()) {
752+
match self.get_env_str(key.as_env_key()) {
752753
Some(value) => {
753754
let definition = Definition::Environment(key.as_env_key().to_string());
754755
Ok(Some(Value {
@@ -768,33 +769,45 @@ impl Config {
768769
/// Get the value of environment variable `key` through the `Config` snapshot.
769770
///
770771
/// This can be used similarly to `std::env::var`.
771-
pub fn get_env(&self, key: impl AsRef<str>) -> CargoResult<String> {
772-
match self.env.get(key.as_ref()) {
773-
Some(s) => Ok(s.clone()),
774-
None => bail!(
775-
"{} could not be found in the environment snapshot",
776-
key.as_ref()
777-
),
772+
pub fn get_env(&self, key: impl AsRef<OsStr>) -> CargoResult<String> {
773+
let key = key.as_ref();
774+
let s = match self.env.get(key) {
775+
Some(s) => s,
776+
None => bail!("{key:?} could not be found in the environment snapshot",),
777+
};
778+
match s.to_str() {
779+
Some(s) => Ok(s.to_owned()),
780+
None => bail!("environment variable value is not valid unicode: {s:?}"),
778781
}
779782
}
780783

781784
/// Get the value of environment variable `key` through the `Config` snapshot.
782785
///
783786
/// This can be used similarly to `std::env::var_os`.
784-
pub fn get_env_os(&self, key: impl AsRef<str>) -> Option<String> {
787+
pub fn get_env_os(&self, key: impl AsRef<OsStr>) -> Option<OsString> {
785788
self.env.get(key.as_ref()).cloned()
786789
}
787790

791+
/// Get the value of environment variable `key`.
792+
/// Returns `None` if `key` is not in `self.env` or if the value is not valid UTF-8.
793+
fn get_env_str(&self, key: impl AsRef<OsStr>) -> Option<&str> {
794+
self.env.get(key.as_ref()).and_then(|s| s.to_str())
795+
}
796+
797+
fn env_has_key(&self, key: impl AsRef<OsStr>) -> bool {
798+
self.env.contains_key(key.as_ref())
799+
}
800+
788801
/// Check if the [`Config`] contains a given [`ConfigKey`].
789802
///
790803
/// See `ConfigMapAccess` for a description of `env_prefix_ok`.
791804
fn has_key(&self, key: &ConfigKey, env_prefix_ok: bool) -> CargoResult<bool> {
792-
if self.env.contains_key(key.as_env_key()) {
805+
if self.env_has_key(key.as_env_key()) {
793806
return Ok(true);
794807
}
795808
if env_prefix_ok {
796809
let env_prefix = format!("{}_", key.as_env_key());
797-
if self.env.keys().any(|k| k.starts_with(&env_prefix)) {
810+
if self.env_keys().any(|k| k.starts_with(&env_prefix)) {
798811
return Ok(true);
799812
}
800813
}
@@ -906,7 +919,7 @@ impl Config {
906919
key: &ConfigKey,
907920
output: &mut Vec<(String, Definition)>,
908921
) -> CargoResult<()> {
909-
let env_val = match self.env.get(key.as_env_key()) {
922+
let env_val = match self.get_env_str(key.as_env_key()) {
910923
Some(v) => v,
911924
None => {
912925
self.check_environment_key_case_mismatch(key);
@@ -1637,7 +1650,7 @@ impl Config {
16371650
) -> Option<PathBuf> {
16381651
let var = tool.to_uppercase();
16391652

1640-
match self.get_env_os(&var) {
1653+
match self.get_env_os(&var).as_ref().and_then(|s| s.to_str()) {
16411654
Some(tool_path) => {
16421655
let maybe_relative = tool_path.contains('/') || tool_path.contains('\\');
16431656
let path = if maybe_relative {

0 commit comments

Comments
 (0)