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

Support deactivating virtual environments without user intervention #22405

Merged
merged 24 commits into from
Nov 10, 2023
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
6 changes: 0 additions & 6 deletions pythonFiles/deactivate.csh

This file was deleted.

36 changes: 0 additions & 36 deletions pythonFiles/deactivate.fish

This file was deleted.

31 changes: 0 additions & 31 deletions pythonFiles/deactivate.ps1

This file was deleted.

44 changes: 44 additions & 0 deletions pythonFiles/deactivate/bash/deactivate
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Same as deactivate in "<venv>/bin/activate"
deactivate () {
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
unset VIRTUAL_ENV_PROMPT
if [ ! "${1:-}" = "nondestructive" ] ; then
unset -f deactivate
fi
}

# Get the directory of the current script
SCRIPT_DIR=$(dirname "$0")
# Construct the path to envVars.txt relative to the script directory
ENV_FILE="$SCRIPT_DIR/envVars.txt"

# Read the JSON file and set the variables
TEMP_PS1=$(grep '^PS1=' $ENV_FILE | cut -d '=' -f 2)
TEMP_PATH=$(grep '^PATH=' $ENV_FILE | cut -d '=' -f 2)
TEMP_PYTHONHOME=$(grep '^PYTHONHOME=' $ENV_FILE | cut -d '=' -f 2)
# Initialize the variables required by deactivate function
_OLD_VIRTUAL_PS1="${TEMP_PS1:-}"
_OLD_VIRTUAL_PATH="$TEMP_PATH"
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${TEMP_PYTHONHOME:-}"
fi
deactivate
bash
44 changes: 44 additions & 0 deletions pythonFiles/deactivate/fish/deactivate
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Same as deactivate in "<venv>/bin/activate"
deactivate () {
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
PATH="${_OLD_VIRTUAL_PATH:-}"
export PATH
unset _OLD_VIRTUAL_PATH
fi
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
export PYTHONHOME
unset _OLD_VIRTUAL_PYTHONHOME
fi
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
hash -r 2> /dev/null
fi
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
unset VIRTUAL_ENV_PROMPT
if [ ! "${1:-}" = "nondestructive" ] ; then
unset -f deactivate
fi
}

# Get the directory of the current script
SCRIPT_DIR=$(dirname "$0")
# Construct the path to envVars.txt relative to the script directory
ENV_FILE="$SCRIPT_DIR/envVars.txt"

# Read the JSON file and set the variables
TEMP_PS1=$(grep '^PS1=' $ENV_FILE | cut -d '=' -f 2)
TEMP_PATH=$(grep '^PATH=' $ENV_FILE | cut -d '=' -f 2)
TEMP_PYTHONHOME=$(grep '^PYTHONHOME=' $ENV_FILE | cut -d '=' -f 2)
# Initialize the variables required by deactivate function
_OLD_VIRTUAL_PS1="${TEMP_PS1:-}"
_OLD_VIRTUAL_PATH="$TEMP_PATH"
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${TEMP_PYTHONHOME:-}"
fi
deactivate
fish
11 changes: 11 additions & 0 deletions pythonFiles/deactivate/powershell/deactivate.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Load dotenv-style file and restore environment variables
Get-Content -Path "$PSScriptRoot\envVars.txt" | ForEach-Object {
# Split each line into key and value at the first '='
$parts = $_ -split '=', 2
if ($parts.Count -eq 2) {
$key = $parts[0].Trim()
$value = $parts[1].Trim()
# Set the environment variable
Set-Item -Path "env:$key" -Value $value
}
}
17 changes: 14 additions & 3 deletions pythonFiles/deactivate → pythonFiles/deactivate/zsh/deactivate
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,20 @@ deactivate () {
fi
}

# Get the directory of the current script
SCRIPT_DIR=$(dirname "$0")
# Construct the path to envVars.txt relative to the script directory
ENV_FILE="$SCRIPT_DIR/envVars.txt"

# Read the JSON file and set the variables
TEMP_PS1=$(grep '^PS1=' $ENV_FILE | cut -d '=' -f 2)
TEMP_PATH=$(grep '^PATH=' $ENV_FILE | cut -d '=' -f 2)
TEMP_PYTHONHOME=$(grep '^PYTHONHOME=' $ENV_FILE | cut -d '=' -f 2)
# Initialize the variables required by deactivate function
_OLD_VIRTUAL_PS1="${PS1:-}"
_OLD_VIRTUAL_PATH="$PATH"
_OLD_VIRTUAL_PS1="${TEMP_PS1:-}"
_OLD_VIRTUAL_PATH="$TEMP_PATH"
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
_OLD_VIRTUAL_PYTHONHOME="${TEMP_PYTHONHOME:-}"
fi
deactivate
zsh

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why run a new shell? Doesn't this stop the deactivate script from returning until the new shell is exited?

11 changes: 5 additions & 6 deletions pythonFiles/printEnvVariablesToFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
# Licensed under the MIT License.

import os
import json
import sys

# Last argument is the target file into which we'll write the env variables line by line.
output_file = sys.argv[-1]

# Last argument is the target file into which we'll write the env variables as json.
json_file = sys.argv[-1]

with open(json_file, "w") as outfile:
json.dump(dict(os.environ), outfile)
with open(output_file, "w") as outfile:
for key, val in os.environ.items():
outfile.write(f"{key}={val}\n")
34 changes: 34 additions & 0 deletions src/client/common/utils/async.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable no-async-promise-executor */
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

Expand Down Expand Up @@ -228,3 +230,35 @@ export async function flattenIterator<T>(iterator: IAsyncIterator<T>): Promise<T
}
return results;
}

/**
* Wait for a condition to be fulfilled within a timeout.
*
* @export
* @param {() => Promise<boolean>} condition
* @param {number} timeoutMs
* @param {string} errorMessage
* @returns {Promise<void>}
*/
export async function waitForCondition(
condition: () => Promise<boolean>,
timeoutMs: number,
errorMessage: string,
): Promise<void> {
return new Promise<void>(async (resolve, reject) => {
const timeout = setTimeout(() => {
clearTimeout(timeout);

clearTimeout(timer);
reject(new Error(errorMessage));
}, timeoutMs);
const timer = setInterval(async () => {
if (!(await condition().catch(() => false))) {
return;
}
clearTimeout(timeout);
clearTimeout(timer);
resolve();
}, 10);
});
}
2 changes: 1 addition & 1 deletion src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export namespace Interpreters {
export const activatingTerminals = l10n.t('Reactivating terminals...');
export const activateTerminalDescription = l10n.t('Activated environment for');
export const terminalEnvVarCollectionPrompt = l10n.t(
'{0} environment was successfully activated, even though {1} may not be present in the terminal prompt. [Learn more](https://aka.ms/vscodePythonTerminalActivation).',
'{0} environment was successfully activated, even though {1} indicator may not be present in the terminal prompt. [Learn more](https://aka.ms/vscodePythonTerminalActivation).',
);
export const terminalDeactivateProgress = l10n.t('Editing {0}...');
export const restartingTerminal = l10n.t('Restarting terminal and deactivating...');
Expand Down
8 changes: 4 additions & 4 deletions src/client/interpreter/activation/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,15 +273,15 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi
}
return undefined;
}
// Run the activate command collect the environment from it.
const activationCommand = fixActivationCommands(activationCommands).join(' && ');
// In order to make sure we know where the environment output is,
// put in a dummy echo we can look for
const commandSeparator = [TerminalShellType.powershell, TerminalShellType.powershellCore].includes(
shellInfo.shellType,
)
? ';'
: '&&';
// Run the activate command collect the environment from it.
const activationCommand = fixActivationCommands(activationCommands).join(` ${commandSeparator} `);
// In order to make sure we know where the environment output is,
// put in a dummy echo we can look for
command = `${activationCommand} ${commandSeparator} echo '${ENVIRONMENT_PREFIX}' ${commandSeparator} python ${args.join(
' ',
)}`;
Expand Down
Loading
Loading