Skip to content
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
55 changes: 49 additions & 6 deletions src/client/envExt/api.internal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { Terminal, Uri } from 'vscode';
import { EventEmitter, Terminal, Uri, Disposable, ConfigurationTarget } from 'vscode';
import { getExtension } from '../common/vscodeApis/extensionsApi';
import {
GetEnvironmentScope,
Expand All @@ -10,8 +10,10 @@ import {
PythonEnvironmentApi,
PythonProcess,
RefreshEnvironmentsScope,
DidChangeEnvironmentEventArgs,
} from './types';
import { executeCommand } from '../common/vscodeApis/commandApis';
import { IInterpreterPathService } from '../common/types';

export const ENVS_EXTENSION_ID = 'ms-python.vscode-python-envs';

Expand All @@ -24,6 +26,17 @@ export function useEnvExtension(): boolean {
return _useExt;
}

const onDidChangeEnvironmentEnvExtEmitter: EventEmitter<DidChangeEnvironmentEventArgs> = new EventEmitter<
DidChangeEnvironmentEventArgs
>();
export function onDidChangeEnvironmentEnvExt(
listener: (e: DidChangeEnvironmentEventArgs) => unknown,
thisArgs?: unknown,
disposables?: Disposable[],
): Disposable {
return onDidChangeEnvironmentEnvExtEmitter.event(listener, thisArgs, disposables);
}

let _extApi: PythonEnvironmentApi | undefined;
export async function getEnvExtApi(): Promise<PythonEnvironmentApi> {
if (_extApi) {
Expand All @@ -33,14 +46,15 @@ export async function getEnvExtApi(): Promise<PythonEnvironmentApi> {
if (!extension) {
throw new Error('Python Environments extension not found.');
}
if (extension?.isActive) {
_extApi = extension.exports as PythonEnvironmentApi;
return _extApi;
if (!extension?.isActive) {
await extension.activate();
}

await extension.activate();

_extApi = extension.exports as PythonEnvironmentApi;
_extApi.onDidChangeEnvironment((e) => {
onDidChangeEnvironmentEnvExtEmitter.fire(e);
});

return _extApi;
}

Expand Down Expand Up @@ -106,3 +120,32 @@ export async function clearCache(): Promise<void> {
await executeCommand('python-envs.clearCache');
}
}

export function registerEnvExtFeatures(
disposables: Disposable[],
interpreterPathService: IInterpreterPathService,
): void {
if (useEnvExtension()) {
disposables.push(
onDidChangeEnvironmentEnvExt(async (e: DidChangeEnvironmentEventArgs) => {
const previousPath = interpreterPathService.get(e.uri);

if (previousPath !== e.new?.environmentPath.fsPath) {
if (e.uri) {
await interpreterPathService.update(
e.uri,
ConfigurationTarget.WorkspaceFolder,
e.new?.environmentPath.fsPath,
);
} else {
await interpreterPathService.update(
undefined,
ConfigurationTarget.Global,
e.new?.environmentPath.fsPath,
);
}
}
}),
);
}
}
15 changes: 14 additions & 1 deletion src/client/environmentApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { PythonEnvInfo, PythonEnvKind, PythonEnvType } from './pythonEnvironment
import { getEnvPath } from './pythonEnvironments/base/info/env';
import { IDiscoveryAPI, ProgressReportStage } from './pythonEnvironments/base/locator';
import { IPythonExecutionFactory } from './common/process/types';
import { traceError, traceVerbose } from './logging';
import { traceError, traceInfo, traceVerbose } from './logging';
import { isParentPath, normCasePath } from './common/platform/fs-paths';
import { sendTelemetryEvent } from './telemetry';
import { EventName } from './telemetry/constants';
Expand Down Expand Up @@ -42,7 +42,13 @@ type ActiveEnvironmentChangeEvent = {
};

const onDidActiveInterpreterChangedEvent = new EventEmitter<ActiveEnvironmentPathChangeEvent>();
const previousEnvMap = new Map<string, string>();
export function reportActiveInterpreterChanged(e: ActiveEnvironmentChangeEvent): void {
const oldPath = previousEnvMap.get(e.resource?.uri.fsPath ?? '');
if (oldPath === e.path) {
return;
}
previousEnvMap.set(e.resource?.uri.fsPath ?? '', e.path);
onDidActiveInterpreterChangedEvent.fire({ id: getEnvID(e.path), path: e.path, resource: e.resource });
reportActiveInterpreterChangedDeprecated({ path: e.path, resource: e.resource?.uri });
}
Expand Down Expand Up @@ -172,6 +178,13 @@ export function buildEnvironmentApi(
}

disposables.push(
onDidActiveInterpreterChangedEvent.event((e) => {
let scope = 'global';
if (e.resource) {
scope = e.resource instanceof Uri ? e.resource.fsPath : e.resource.uri.fsPath;
}
traceInfo(`Active interpreter [${scope}]: `, e.path);
}),
discoveryApi.onProgress((e) => {
if (e.stage === ProgressReportStage.discoveryFinished) {
knownCache = initKnownCache();
Expand Down
2 changes: 2 additions & 0 deletions src/client/extensionActivation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { registerTriggerForTerminalREPL } from './terminals/codeExecution/termin
import { registerPythonStartup } from './terminals/pythonStartup';
import { registerPixiFeatures } from './pythonEnvironments/common/environmentManagers/pixi';
import { registerCustomTerminalLinkProvider } from './terminals/pythonStartupLinkProvider';
import { registerEnvExtFeatures } from './envExt/api.internal';

export async function activateComponents(
// `ext` is passed to any extra activation funcs.
Expand Down Expand Up @@ -101,6 +102,7 @@ export function activateFeatures(ext: ExtensionState, _components: Components):
const interpreterService: IInterpreterService = ext.legacyIOC.serviceContainer.get<IInterpreterService>(
IInterpreterService,
);
registerEnvExtFeatures(ext.disposables, interpreterPathService);
const pathUtils = ext.legacyIOC.serviceContainer.get<IPathUtils>(IPathUtils);
registerPixiFeatures(ext.disposables);
registerAllCreateEnvironmentFeatures(
Expand Down
9 changes: 9 additions & 0 deletions src/test/common/persistentState.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { assert, expect } from 'chai';
import * as TypeMoq from 'typemoq';
import * as sinon from 'sinon';
import { Memento } from 'vscode';
import { ICommandManager } from '../../client/common/application/types';
import { Commands } from '../../client/common/constants';
Expand All @@ -17,17 +18,25 @@ import {
import { IDisposable } from '../../client/common/types';
import { sleep } from '../core';
import { MockMemento } from '../mocks/mementos';
import * as apiInt from '../../client/envExt/api.internal';

suite('Persistent State', () => {
let cmdManager: TypeMoq.IMock<ICommandManager>;
let persistentStateFactory: PersistentStateFactory;
let workspaceMemento: Memento;
let globalMemento: Memento;
let useEnvExtensionStub: sinon.SinonStub;
setup(() => {
cmdManager = TypeMoq.Mock.ofType<ICommandManager>();
workspaceMemento = new MockMemento();
globalMemento = new MockMemento();
persistentStateFactory = new PersistentStateFactory(globalMemento, workspaceMemento, cmdManager.object);

useEnvExtensionStub = sinon.stub(apiInt, 'useEnvExtension');
useEnvExtensionStub.returns(false);
});
teardown(() => {
sinon.restore();
});

test('Global states created are restored on invoking clean storage command', async () => {
Expand Down
Loading