From 252304e05ed194e05421db3e844cde81071730c1 Mon Sep 17 00:00:00 2001 From: Swastik Patel Date: Thu, 24 Apr 2025 00:40:06 +0530 Subject: [PATCH 1/2] feat: Add generate_deactivation_script function --- src/cli/shell_hook.rs | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/cli/shell_hook.rs b/src/cli/shell_hook.rs index f5e5b4b916..86fa8b9a10 100644 --- a/src/cli/shell_hook.rs +++ b/src/cli/shell_hook.rs @@ -57,6 +57,10 @@ pub struct Args { #[clap(long, default_value = "false", conflicts_with = "shell")] json: bool, + /// Generate a deactivation script instead of an activation script + #[clap(long, default_value = "false", conflicts_with = "json")] + deactivate: bool, + #[clap(flatten)] prompt_config: ConfigCliPrompt, } @@ -117,6 +121,29 @@ async fn generate_activation_script( } } +/// Generates the deactivation script. +async fn generate_deactivation_script( + shell: Option, + environment: &Environment<'_>, + _project: &Workspace, +) -> miette::Result { + // Get shell from the arguments or from the current process or use default if + // all fails + let shell = shell.unwrap_or_else(|| { + ShellEnum::from_parent_process() + .unwrap_or_else(|| ShellEnum::from_env().unwrap_or_default()) + }); + + let activator = get_activator(environment, shell.clone()).into_diagnostic()?; + + // Use the deactivation method + let result = activator.deactivation().into_diagnostic()?; + + let script = result.script.contents().into_diagnostic()?; + + Ok(script.to_string()) +} + /// Generates a JSON object describing the changes to the shell environment when /// activating the provided pixi environment. async fn generate_environment_json( @@ -168,8 +195,9 @@ pub async fn execute(args: Args) -> miette::Result<()> { ) .await?; - let output = match args.json { - true => { + let output = match (args.json, args.deactivate) { + (true, _) => { + // JSON mode takes precedence over deactivate (they are mutually exclusive anyway) generate_environment_json( &environment, &lock_file_data.lock_file, @@ -178,9 +206,14 @@ pub async fn execute(args: Args) -> miette::Result<()> { ) .await? } - // Skipping the activated environment caching for the script. - // As it can still run scripts. - false => generate_activation_script(args.shell, &environment, &workspace).await?, + (_, true) => { + // Deactivation script + generate_deactivation_script(args.shell, &environment, &workspace).await? + } + _ => { + // Default: activation script + generate_activation_script(args.shell, &environment, &workspace).await? + } }; // Print the output - either a JSON object or a shell script From 54685c3dd9133386dd6410d839b397ff9dac6287 Mon Sep 17 00:00:00 2001 From: Swastik Patel Date: Tue, 29 Apr 2025 02:48:36 +0530 Subject: [PATCH 2/2] refactor: allow env_vars to restore to pre-activation state --- src/activation.rs | 3 +++ src/cli/shell_hook.rs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/activation.rs b/src/activation.rs index 5c1bed1eb1..79b37af3cc 100644 --- a/src/activation.rs +++ b/src/activation.rs @@ -285,6 +285,9 @@ pub async fn run_activation( // Prepending environment paths so they get found first. path_modification_behavior, + + // Current environment variables + current_env: HashMap::new(), }, None, ) diff --git a/src/cli/shell_hook.rs b/src/cli/shell_hook.rs index 86fa8b9a10..3fb6da5f43 100644 --- a/src/cli/shell_hook.rs +++ b/src/cli/shell_hook.rs @@ -83,6 +83,9 @@ async fn generate_activation_script( .unwrap_or_else(|| ShellEnum::from_env().unwrap_or_default()) }); + // Read current environment variables + let current_env = std::env::vars().collect::>(); + let activator = get_activator(environment, shell.clone()).into_diagnostic()?; let path = std::env::var("PATH") @@ -97,6 +100,7 @@ async fn generate_activation_script( conda_prefix, path, path_modification_behavior: PathModificationBehavior::default(), + current_env, }) .into_diagnostic()?;