Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Command::get_envs in env_var #3208

Merged
merged 1 commit into from
Feb 12, 2023
Merged
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
152 changes: 7 additions & 145 deletions src/env_var.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,13 @@
use std::collections::{HashSet, VecDeque};
use std::collections::VecDeque;
use std::env;
use std::ffi::OsStr;
use std::path::PathBuf;
use std::process::Command;

use crate::process;

pub const RUST_RECURSION_COUNT_MAX: u32 = 20;

/// This can be removed when https://github.com/rust-lang/rust/issues/44434 is
/// stablised.
pub(crate) trait ProcessEnvs {
fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
where
Self: Sized,
K: AsRef<OsStr>,
V: AsRef<OsStr>;
}

impl ProcessEnvs for Command {
fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
where
Self: Sized,
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
self.env(key, val)
}
}

#[allow(unused)]
fn append_path<E: ProcessEnvs>(name: &str, value: Vec<PathBuf>, cmd: &mut E) {
let old_value = process().var_os(name);
let mut parts: Vec<PathBuf>;
if let Some(ref v) = old_value {
let old_paths: Vec<PathBuf> = env::split_paths(v).collect::<Vec<_>>();
parts = concat_uniq_paths(old_paths, value);
} else {
parts = value;
}
if let Ok(new_value) = env::join_paths(parts) {
cmd.env(name, new_value);
}
}

pub(crate) fn prepend_path<E: ProcessEnvs>(name: &str, prepend: Vec<PathBuf>, cmd: &mut E) {
pub(crate) fn prepend_path(name: &str, prepend: Vec<PathBuf>, cmd: &mut Command) {
let old_value = process().var_os(name);
let parts = if let Some(ref v) = old_value {
let mut tail = env::split_paths(v).collect::<VecDeque<_>>();
Expand Down Expand Up @@ -73,117 +36,15 @@ pub(crate) fn inc(name: &str, cmd: &mut Command) {
cmd.env(name, (old_value + 1).to_string());
}

fn concat_uniq_paths(fst_paths: Vec<PathBuf>, snd_paths: Vec<PathBuf>) -> Vec<PathBuf> {
let deduped_fst_paths = dedupe_with_preserved_order(fst_paths);
let deduped_snd_paths = dedupe_with_preserved_order(snd_paths);

let vec_fst_paths: Vec<_> = deduped_fst_paths.into_iter().collect();

let mut unified_paths;
unified_paths = vec_fst_paths.clone();
unified_paths.extend(
deduped_snd_paths
.into_iter()
.filter(|v| !vec_fst_paths.contains(v))
.collect::<Vec<_>>(),
);

unified_paths
}

fn dedupe_with_preserved_order(paths: Vec<PathBuf>) -> Vec<PathBuf> {
let mut uniq_paths: Vec<PathBuf> = Vec::new();
let mut seen_paths: HashSet<PathBuf> = HashSet::new();

for path in &paths {
if !seen_paths.contains(path) {
seen_paths.insert(path.to_path_buf());
uniq_paths.push(path.to_path_buf());
}
}

uniq_paths
}

#[cfg(test)]
mod tests {
use super::*;
use crate::currentprocess;
use crate::test::{with_saved_path, Env};

use super::ProcessEnvs;
use std::collections::HashMap;
use std::ffi::{OsStr, OsString};

#[derive(Default)]
struct TestCommand {
envs: HashMap<OsString, Option<OsString>>,
}

impl ProcessEnvs for TestCommand {
fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
where
Self: Sized,
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
self.envs
.insert(key.as_ref().to_owned(), Some(val.as_ref().to_owned()));
self
}
}

#[test]
fn deduplicate_and_concat_paths() {
let mut old_paths = vec![];

let z = OsString::from("/home/z/.cargo/bin");
let path_z = PathBuf::from(z);
old_paths.push(path_z);

let a = OsString::from("/home/a/.cargo/bin");
let path_a = PathBuf::from(a);
old_paths.push(path_a);

let _a = OsString::from("/home/a/.cargo/bin");
let _path_a = PathBuf::from(_a);
old_paths.push(_path_a);

let mut new_paths = vec![];

let n = OsString::from("/home/n/.cargo/bin");
let path_n = PathBuf::from(n);
new_paths.push(path_n);

let g = OsString::from("/home/g/.cargo/bin");
let path_g = PathBuf::from(g);
new_paths.push(path_g);

let _g = OsString::from("/home/g/.cargo/bin");
let _path_g = PathBuf::from(_g);
new_paths.push(_path_g);

let _z = OsString::from("/home/z/.cargo/bin");
let path_z = PathBuf::from(_z);
old_paths.push(path_z);

let mut unified_paths: Vec<PathBuf> = vec![];
let zpath = OsString::from("/home/z/.cargo/bin");
let _zpath = PathBuf::from(zpath);
unified_paths.push(_zpath);
let apath = OsString::from("/home/a/.cargo/bin");
let _apath = PathBuf::from(apath);
unified_paths.push(_apath);
let npath = OsString::from("/home/n/.cargo/bin");
let _npath = PathBuf::from(npath);
unified_paths.push(_npath);
let gpath = OsString::from("/home/g/.cargo/bin");
let _gpath = PathBuf::from(gpath);
unified_paths.push(_gpath);

assert_eq!(concat_uniq_paths(old_paths, new_paths), unified_paths);
}

#[test]
fn prepend_unique_path() {
let mut vars = HashMap::new();
Expand All @@ -198,7 +59,7 @@ mod tests {
with_saved_path(&|| {
currentprocess::with(tp.clone(), || {
let mut path_entries = vec![];
let mut cmd = TestCommand::default();
let mut cmd = Command::new("test");

let a = OsString::from("/home/a/.cargo/bin");
let path_a = PathBuf::from(a);
Expand All @@ -213,13 +74,13 @@ mod tests {
path_entries.push(path_z);

prepend_path("PATH", path_entries, &mut cmd);
let envs: Vec<_> = cmd.envs.iter().collect();
let envs: Vec<_> = cmd.get_envs().collect();

assert_eq!(
envs,
&[(
&OsString::from("PATH"),
&Some(
OsStr::new("PATH"),
Some(
env::join_paths(
vec![
"/home/z/.cargo/bin",
Expand All @@ -229,6 +90,7 @@ mod tests {
.iter()
)
.unwrap()
.as_os_str()
)
),]
);
Expand Down