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

fix: make sure pixi vars are available before activation.env vars are… #1740

Merged
Merged
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
51 changes: 43 additions & 8 deletions src/activation.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use indexmap::IndexMap;
use std::collections::HashMap;

use itertools::Itertools;
Expand Down Expand Up @@ -68,21 +69,23 @@ const ENV_PREFIX: &str = "PIXI_ENVIRONMENT_";

impl Environment<'_> {
/// Returns environment variables and their values that should be injected when running a command.
pub fn get_metadata_env(&self) -> HashMap<String, String> {
pub fn get_metadata_env(&self) -> IndexMap<String, String> {
let prompt = match self.name() {
EnvironmentName::Named(name) => {
format!("{}:{}", self.project().name(), name)
}
EnvironmentName::Default => self.project().name().to_string(),
};
let mut map = HashMap::from_iter([
let mut map = IndexMap::from_iter([
(format!("{ENV_PREFIX}NAME"), self.name().to_string()),
(
format!("{ENV_PREFIX}PLATFORMS"),
self.platforms().iter().map(|plat| plat.as_str()).join(","),
),
("PIXI_PROMPT".to_string(), format!("({}) ", prompt)),
]);

// Add the activation environment variables
map.extend(self.activation_env(Some(Platform::current())));
map
}
Expand Down Expand Up @@ -211,15 +214,13 @@ pub async fn run_activation(
}

/// Get the environment variables that are statically generated from the project and the environment.
/// Returns IndexMap to stay sorted, as pixi should export the metadata before exporting variables that could depend on it.
pub fn get_static_environment_variables<'p>(
environment: &'p Environment<'p>,
) -> HashMap<String, String> {
// Get environment variables from the project
) -> IndexMap<String, String> {
// Get environment variables from the pixi project meta data
let project_env = environment.project().get_metadata_env();

// Get environment variables from the environment
let environment_env = environment.get_metadata_env();

// Add the conda default env variable so that the existing tools know about the env.
let env_name = match environment.name() {
EnvironmentName::Named(name) => format!("{}:{}", environment.project().name(), name),
Expand All @@ -228,11 +229,14 @@ pub fn get_static_environment_variables<'p>(
let mut shell_env = HashMap::new();
shell_env.insert("CONDA_DEFAULT_ENV".to_string(), env_name);

// Get environment variables from the pixi environment
let environment_env = environment.get_metadata_env();

// Combine the environments
project_env
.into_iter()
.chain(environment_env)
.chain(shell_env)
.chain(environment_env)
.collect()
}

Expand Down Expand Up @@ -375,6 +379,37 @@ mod tests {
);
}

#[test]
fn test_metadata_project_env_order() {
let project = r#"
[project]
name = "pixi"
channels = [""]
platforms = ["linux-64", "osx-64", "win-64"]

[activation.env]
ABC = "123test123"
ZZZ = "123test123"
ZAB = "123test123"
"#;
let project = Project::from_str(Path::new("pixi.toml"), project).unwrap();
let env = get_static_environment_variables(&project.default_environment());

// Make sure the user defined environment variables are at the end.
assert!(
env.keys().position(|key| key == "PIXI_PROJECT_NAME")
< env.keys().position(|key| key == "ABC")
);
assert!(
env.keys().position(|key| key == "PIXI_PROJECT_NAME")
< env.keys().position(|key| key == "ZZZ")
);

// Make sure the user defined environment variables are sorted by input order.
assert!(env.keys().position(|key| key == "ABC") < env.keys().position(|key| key == "ZZZ"));
assert!(env.keys().position(|key| key == "ZZZ") < env.keys().position(|key| key == "ZAB"));
}

#[test]
#[cfg(target_os = "unix")]
fn test_get_linux_clean_environment_variables() {
Expand Down
5 changes: 3 additions & 2 deletions src/project/environment.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use indexmap::IndexMap;
use std::{
collections::{HashMap, HashSet},
fmt::Debug,
Expand Down Expand Up @@ -246,10 +247,10 @@ impl<'p> Environment<'p> {
///
/// The environment variables of all features are combined in the order they
/// are defined for the environment.
pub fn activation_env(&self, platform: Option<Platform>) -> HashMap<String, String> {
pub fn activation_env(&self, platform: Option<Platform>) -> IndexMap<String, String> {
self.features()
.filter_map(|f| f.activation_env(platform))
.fold(HashMap::new(), |mut acc, env| {
.fold(IndexMap::new(), |mut acc, env| {
acc.extend(env.iter().map(|(k, v)| (k.clone(), v.clone())));
acc
})
Expand Down
Loading