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

Guide users to install workaround when deactivate command is run #22223

Merged
merged 39 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ce4da13
Intial commit
Oct 13, 2023
70b6fcd
Do not prepend twice
Oct 14, 2023
c839ca9
Add deactivate prompt
Oct 14, 2023
ba8d8d5
Cleean up
Oct 14, 2023
eb0b909
More changes
Oct 14, 2023
11f789a
Yes
Oct 14, 2023
bca27e1
Changes based on powershell
Oct 14, 2023
91d634c
Log when not in experiment due to multiroot+scenario scenario
Oct 14, 2023
1c6a8bc
Log process variables at the start
Oct 14, 2023
648c6ac
Use worksapceFolder to judge mutlirootworkspace
Oct 14, 2023
8aaf46c
Fine tuen
Oct 14, 2023
dff84dc
Add progress notification
Oct 14, 2023
881c8d4
Make progress nicer
Oct 14, 2023
18ac7ee
Nit
Oct 14, 2023
4959e4d
Add tests for progress service
Oct 14, 2023
72a80a7
Fix activating using command when deactivate is in place
Oct 15, 2023
5e05dc0
Don't hide progress bar in case of errror
Oct 15, 2023
cb2b314
Hey
Oct 15, 2023
b71fb93
Merge branch 'kartik/grotesque-cougar' of https://github.com/microsof…
Oct 15, 2023
7649be7
Add unit tests
Oct 18, 2023
ba3fbdc
Fit
Oct 18, 2023
119dc98
Restore
Oct 18, 2023
469dc44
copyfile
Oct 19, 2023
c2ccce9
restore filesystem
Oct 19, 2023
f6f82ba
commnet
Oct 19, 2023
80f8b1b
Add unit test
Oct 19, 2023
1f98888
join paths appropriately
Oct 19, 2023
4bbb7e2
Remove flaky test
Oct 19, 2023
efed9b7
disable terminal deactivate test
Oct 19, 2023
f9e6c38
OPEN IN SAME WINDOW
Oct 19, 2023
9025758
god
Oct 19, 2023
96ed687
Fix bugs
Oct 19, 2023
c0d853f
run all
Oct 19, 2023
3891fde
workaround bash macos zsh situation
Oct 19, 2023
d805e48
Add unit test
Oct 20, 2023
a52599f
Hey
Oct 20, 2023
4e57ed9
Reveal the edit in a nicer way
Oct 20, 2023
151c16e
Restart shell when deactivaate command is run again for the same shell
Oct 20, 2023
cd72b0b
Add test
Oct 20, 2023
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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"quickPickSortByLabel",
"testObserver",
"quickPickItemTooltip",
"saveEditor"
"saveEditor",
"terminalDataWriteEvent"
],
"author": {
"name": "Microsoft Corporation"
Expand Down
33 changes: 33 additions & 0 deletions pythonFiles/deactivate
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 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
}

# Initialize the variables required by deactivate function
_OLD_VIRTUAL_PS1="${PS1:-}"
_OLD_VIRTUAL_PATH="$PATH"
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
fi
6 changes: 6 additions & 0 deletions pythonFiles/deactivate.csh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Same as deactivate in "<venv>/bin/activate.csh"
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'

# Initialize the variables required by deactivate function
set _OLD_VIRTUAL_PROMPT="$prompt"
set _OLD_VIRTUAL_PATH="$PATH"
36 changes: 36 additions & 0 deletions pythonFiles/deactivate.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Same as deactivate in "<venv>/bin/activate.fish"
function deactivate -d "Exit virtual environment and return to normal shell environment"
# reset old environment variables
if test -n "$_OLD_VIRTUAL_PATH"
set -gx PATH $_OLD_VIRTUAL_PATH
set -e _OLD_VIRTUAL_PATH
end
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
set -e _OLD_VIRTUAL_PYTHONHOME
end

if test -n "$vscode_python_old_fish_prompt_OVERRIDE"
set -e vscode_python_old_fish_prompt_OVERRIDE
if functions -q vscode_python_old_fish_prompt
functions -e fish_prompt
functions -c vscode_python_old_fish_prompt fish_prompt
functions -e vscode_python_old_fish_prompt
end
end

set -e VIRTUAL_ENV
set -e VIRTUAL_ENV_PROMPT
if test "$argv[1]" != "nondestructive"
functions -e deactivate
end
end

# Initialize the variables required by deactivate function
set -gx _OLD_VIRTUAL_PATH $PATH
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
functions -c fish_prompt vscode_python_old_fish_prompt
end
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
end
31 changes: 31 additions & 0 deletions pythonFiles/deactivate.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Same as deactivate in "Activate.ps1"
function global:deactivate ([switch]$NonDestructive) {
if (Test-Path function:_OLD_VIRTUAL_PROMPT) {
copy-item function:_OLD_VIRTUAL_PROMPT function:prompt
remove-item function:_OLD_VIRTUAL_PROMPT
}
if (Test-Path env:_OLD_VIRTUAL_PYTHONHOME) {
copy-item env:_OLD_VIRTUAL_PYTHONHOME env:PYTHONHOME
remove-item env:_OLD_VIRTUAL_PYTHONHOME
}
if (Test-Path env:_OLD_VIRTUAL_PATH) {
copy-item env:_OLD_VIRTUAL_PATH env:PATH
remove-item env:_OLD_VIRTUAL_PATH
}
if (Test-Path env:VIRTUAL_ENV) {
remove-item env:VIRTUAL_ENV
}
if (!$NonDestructive) {
remove-item function:deactivate
}
}

# Initialize the variables required by deactivate function
if (! $env:VIRTUAL_ENV_DISABLE_PROMPT) {
function global:_OLD_VIRTUAL_PROMPT {""}
copy-item function:prompt function:_OLD_VIRTUAL_PROMPT
}
if (Test-Path env:PYTHONHOME) {
copy-item env:PYTHONHOME env:_OLD_VIRTUAL_PYTHONHOME
}
copy-item env:PATH env:_OLD_VIRTUAL_PATH
12 changes: 11 additions & 1 deletion src/client/common/application/applicationShell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
DocumentSelector,
env,
Event,
EventEmitter,
InputBox,
InputBoxOptions,
languages,
Expand Down Expand Up @@ -37,7 +38,8 @@ import {
WorkspaceFolder,
WorkspaceFolderPickOptions,
} from 'vscode';
import { IApplicationShell } from './types';
import { traceError } from '../../logging';
import { IApplicationShell, TerminalDataWriteEvent } from './types';

@injectable()
export class ApplicationShell implements IApplicationShell {
Expand Down Expand Up @@ -172,4 +174,12 @@ export class ApplicationShell implements IApplicationShell {
public createLanguageStatusItem(id: string, selector: DocumentSelector): LanguageStatusItem {
return languages.createLanguageStatusItem(id, selector);
}
public get onDidWriteTerminalData(): Event<TerminalDataWriteEvent> {
try {
return window.onDidWriteTerminalData;
} catch (ex) {
traceError('Failed to get proposed API onDidWriteTerminalData', ex);
return new EventEmitter<TerminalDataWriteEvent>().event;
}
}
}
32 changes: 32 additions & 0 deletions src/client/common/application/progressService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { ProgressOptions } from 'vscode';
import { Deferred, createDeferred } from '../utils/async';
import { IApplicationShell } from './types';

export class ProgressService {
private deferred: Deferred<void> | undefined;

constructor(private readonly shell: IApplicationShell) {}

public showProgress(options: ProgressOptions): void {
if (!this.deferred) {
this.createProgress(options);
}
}

public hideProgress(): void {
if (this.deferred) {
this.deferred.resolve();
this.deferred = undefined;
}
}

private createProgress(options: ProgressOptions) {
this.shell.withProgress(options, () => {
this.deferred = createDeferred();
return this.deferred.promise;
});
}
}
18 changes: 18 additions & 0 deletions src/client/common/application/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ import { Resource } from '../types';
import { ICommandNameArgumentTypeMapping } from './commands';
import { ExtensionContextKey } from './contextKeys';

export interface TerminalDataWriteEvent {
/**
* The {@link Terminal} for which the data was written.
*/
readonly terminal: Terminal;
/**
* The data being written.
*/
readonly data: string;
}

export const IApplicationShell = Symbol('IApplicationShell');
export interface IApplicationShell {
/**
Expand All @@ -75,6 +86,13 @@ export interface IApplicationShell {
*/
readonly onDidChangeWindowState: Event<WindowState>;

/**
* An event which fires when the terminal's child pseudo-device is written to (the shell).
* In other words, this provides access to the raw data stream from the process running
* within the terminal, including VT sequences.
*/
readonly onDidWriteTerminalData: Event<TerminalDataWriteEvent>;

showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined>;

/**
Expand Down
4 changes: 3 additions & 1 deletion src/client/common/experiments/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import { env, workspace } from 'vscode';
import { IExperimentService } from '../types';
import { TerminalEnvVarActivation } from './groups';
import { isTestExecution } from '../constants';
import { traceInfo } from '../../logging';

export function inTerminalEnvVarExperiment(experimentService: IExperimentService): boolean {
if (!isTestExecution() && workspace.workspaceFile && env.remoteName) {
if (!isTestExecution() && env.remoteName && workspace.workspaceFolders && workspace.workspaceFolders.length > 1) {
// TODO: Remove this if statement once https://github.com/microsoft/vscode/issues/180486 is fixed.
traceInfo('Not enabling terminal env var experiment in multiroot remote workspaces');
return false;
}
if (!experimentService.inExperimentSync(TerminalEnvVarActivation.experiment)) {
Expand Down
20 changes: 20 additions & 0 deletions src/client/common/platform/fs-paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import * as nodepath from 'path';
import { getSearchPathEnvVarNames } from '../utils/exec';
import * as fs from 'fs-extra';
import { getOSType, OSType } from '../utils/platform';
import { IExecutables, IFileSystemPaths, IFileSystemPathUtils } from './types';

Expand Down Expand Up @@ -170,3 +171,22 @@ export function isParentPath(filePath: string, parentPath: string): boolean {
export function arePathsSame(path1: string, path2: string): boolean {
return normCasePath(path1) === normCasePath(path2);
}

export async function copyFile(src: string, dest: string): Promise<void> {
const destDir = nodepath.dirname(dest);
if (!(await fs.pathExists(destDir))) {
await fs.mkdirp(destDir);
}

await fs.copy(src, dest, {
overwrite: true,
});
}

export function pathExists(absPath: string): Promise<boolean> {
return fs.pathExists(absPath);
}

export function createFile(filename: string): Promise<void> {
return fs.createFile(filename);
}
6 changes: 6 additions & 0 deletions src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export namespace Common {
export const noIWillDoItLater = l10n.t('No, I will do it later');
export const notNow = l10n.t('Not now');
export const doNotShowAgain = l10n.t("Don't show again");
export const editSomething = l10n.t('Edit {0}');
export const reload = l10n.t('Reload');
export const moreInfo = l10n.t('More Info');
export const learnMore = l10n.t('Learn more');
Expand Down Expand Up @@ -198,6 +199,11 @@ export namespace Interpreters {
export const terminalEnvVarCollectionPrompt = l10n.t(
'The Python extension automatically activates all terminals using the selected environment, even when the name of the environment{0} is not 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...');
export const terminalDeactivatePrompt = l10n.t(
'Deactivating virtual environments may not work by default due to a technical limitation in our activation approach, but it can be resolved by appending a line to "{0}". Be sure to restart the shell afterward. [Learn more](https://aka.ms/AAmx2ft).',
);
export const activatedCondaEnvLaunch = l10n.t(
'We noticed VS Code was launched from an activated conda environment, would you like to select it?',
);
Expand Down
8 changes: 0 additions & 8 deletions src/client/interpreter/activation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,3 @@ export interface IEnvironmentActivationService {
interpreter?: PythonEnvironment,
): Promise<string[] | undefined>;
}

export const ITerminalEnvVarCollectionService = Symbol('ITerminalEnvVarCollectionService');
export interface ITerminalEnvVarCollectionService {
/**
* Returns true if we know with high certainity the terminal prompt is set correctly for a particular resource.
*/
isTerminalPromptSetCorrectly(resource?: Resource): boolean;
}
13 changes: 1 addition & 12 deletions src/client/interpreter/serviceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
import { IExtensionActivationService, IExtensionSingleActivationService } from '../activation/types';
import { IServiceManager } from '../ioc/types';
import { EnvironmentActivationService } from './activation/service';
import { TerminalEnvVarCollectionPrompt } from './activation/terminalEnvVarCollectionPrompt';
import { TerminalEnvVarCollectionService } from './activation/terminalEnvVarCollectionService';
import { IEnvironmentActivationService, ITerminalEnvVarCollectionService } from './activation/types';
import { IEnvironmentActivationService } from './activation/types';
import { InterpreterAutoSelectionService } from './autoSelection/index';
import { InterpreterAutoSelectionProxyService } from './autoSelection/proxy';
import { IInterpreterAutoSelectionService, IInterpreterAutoSelectionProxyService } from './autoSelection/types';
Expand Down Expand Up @@ -110,13 +108,4 @@ export function registerTypes(serviceManager: IServiceManager): void {
IEnvironmentActivationService,
EnvironmentActivationService,
);
serviceManager.addSingleton<ITerminalEnvVarCollectionService>(
ITerminalEnvVarCollectionService,
TerminalEnvVarCollectionService,
);
serviceManager.addBinding(ITerminalEnvVarCollectionService, IExtensionActivationService);
serviceManager.addSingleton<IExtensionSingleActivationService>(
IExtensionSingleActivationService,
TerminalEnvVarCollectionPrompt,
);
}
5 changes: 4 additions & 1 deletion src/client/interpreter/virtualEnvs/activatedEnvLaunch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ export class ActivatedEnvironmentLaunch implements IActivatedEnvironmentLaunch {
}
if (process.env.VSCODE_CLI !== '1') {
// We only want to select the interpreter if VS Code was launched from the command line.
traceVerbose('VS Code was not launched from the command line, not selecting activated interpreter');
traceVerbose(
'VS Code was not launched from the command line, not selecting activated interpreter',
JSON.stringify(process.env, undefined, 4),
);
return undefined;
}
const prefix = await this.getPrefixOfSelectedActivatedEnv();
Expand Down
Loading