From 30f7096942762dc5324ab68d085b88620b505fbd Mon Sep 17 00:00:00 2001 From: Kartik Raj Date: Thu, 12 Jan 2023 22:12:51 +0530 Subject: [PATCH] Initial commit --- src/client/interpreter/activation/service.ts | 35 ++++++++++++++++++-- src/client/interpreter/contracts.ts | 2 +- src/client/interpreter/interpreterService.ts | 6 ++-- src/client/jupyter/jupyterIntegration.ts | 2 +- src/test/linters/lint.provider.test.ts | 5 +-- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/client/interpreter/activation/service.ts b/src/client/interpreter/activation/service.ts index e4074b0708537..635b68e31f877 100644 --- a/src/client/interpreter/activation/service.ts +++ b/src/client/interpreter/activation/service.ts @@ -11,7 +11,7 @@ import { IPlatformService } from '../../common/platform/types'; import * as internalScripts from '../../common/process/internal/scripts'; import { ExecutionResult, IProcessServiceFactory } from '../../common/process/types'; import { ITerminalHelper, TerminalShellType } from '../../common/terminal/types'; -import { ICurrentProcess, IDisposable, Resource } from '../../common/types'; +import { ICurrentProcess, IDisposable, IExtensionContext, Resource } from '../../common/types'; import { sleep } from '../../common/utils/async'; import { InMemoryCache } from '../../common/utils/cacheUtils'; import { OSType } from '../../common/utils/platform'; @@ -102,6 +102,7 @@ export class EnvironmentActivationServiceCache { @injectable() export class EnvironmentActivationService implements IEnvironmentActivationService, IDisposable { private readonly disposables: IDisposable[] = []; + private previousEnvVars = process.env; private readonly activatedEnvVariablesCache = new EnvironmentActivationServiceCache(); constructor( @inject(ITerminalHelper) private readonly helper: ITerminalHelper, @@ -111,6 +112,7 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi @inject(IWorkspaceService) private workspace: IWorkspaceService, @inject(IInterpreterService) private interpreterService: IInterpreterService, @inject(IEnvironmentVariablesProvider) private readonly envVarsService: IEnvironmentVariablesProvider, + @inject(IExtensionContext) private context: IExtensionContext, ) { this.envVarsService.onDidEnvironmentVariablesChange( () => this.activatedEnvVariablesCache.clear(), @@ -119,10 +121,15 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi ); this.interpreterService.onDidChangeInterpreter( - () => this.activatedEnvVariablesCache.clear(), + async (resource) => { + this.activatedEnvVariablesCache.clear(); + await this.initializeEnvironmentCollection(resource); + }, this, this.disposables, ); + + this.initializeEnvironmentCollection(undefined).ignoreErrors(); } public dispose(): void { @@ -322,4 +329,28 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi const js = output.substring(output.indexOf('{')).trim(); return parse(js); } + + private async initializeEnvironmentCollection(resource: Resource) { + const env = await this.getActivatedEnvironmentVariables(resource); + if (!env) { + this.context.environmentVariableCollection.clear(); + this.previousEnvVars = process.env; + return; + } + const previousEnv = this.previousEnvVars; + Object.keys(previousEnv).forEach((key) => { + // If the previous env var is not in the current env, then explicitly add it so it can cleared later. + if (!(key in env)) { + env[key] = ''; + } + }); + this.previousEnvVars = env; + for (const key in env) { + const value = env[key]; + const prevValue = previousEnv[key]; + if (value !== undefined && prevValue !== value) { + this.context.environmentVariableCollection.replace(key, value); + } + } + } } diff --git a/src/client/interpreter/contracts.ts b/src/client/interpreter/contracts.ts index a79a5250ec99b..6cf36c9d77971 100644 --- a/src/client/interpreter/contracts.ts +++ b/src/client/interpreter/contracts.ts @@ -76,7 +76,7 @@ export interface IInterpreterService { readonly refreshPromise: Promise | undefined; readonly onDidChangeInterpreters: Event; onDidChangeInterpreterConfiguration: Event; - onDidChangeInterpreter: Event; + onDidChangeInterpreter: Event; onDidChangeInterpreterInformation: Event; /** * Note this API does not trigger the refresh but only works with the current refresh if any. Information diff --git a/src/client/interpreter/interpreterService.ts b/src/client/interpreter/interpreterService.ts index 50545558d721b..0eff4e584d77d 100644 --- a/src/client/interpreter/interpreterService.ts +++ b/src/client/interpreter/interpreterService.ts @@ -57,7 +57,7 @@ export class InterpreterService implements Disposable, IInterpreterService { return this.pyenvs.getRefreshPromise(); } - public get onDidChangeInterpreter(): Event { + public get onDidChangeInterpreter(): Event { return this.didChangeInterpreterEmitter.event; } @@ -79,7 +79,7 @@ export class InterpreterService implements Disposable, IInterpreterService { private readonly interpreterPathService: IInterpreterPathService; - private readonly didChangeInterpreterEmitter = new EventEmitter(); + private readonly didChangeInterpreterEmitter = new EventEmitter(); private readonly didChangeInterpreterInformation = new EventEmitter(); @@ -219,7 +219,7 @@ export class InterpreterService implements Disposable, IInterpreterService { this.didChangeInterpreterConfigurationEmitter.fire(resource); if (this._pythonPathSetting === '' || this._pythonPathSetting !== pySettings.pythonPath) { this._pythonPathSetting = pySettings.pythonPath; - this.didChangeInterpreterEmitter.fire(); + this.didChangeInterpreterEmitter.fire(resource); reportActiveInterpreterChanged({ path: pySettings.pythonPath, resource: this.serviceContainer.get(IWorkspaceService).getWorkspaceFolder(resource), diff --git a/src/client/jupyter/jupyterIntegration.ts b/src/client/jupyter/jupyterIntegration.ts index 556ff93f240a0..aedc24b1e8bff 100644 --- a/src/client/jupyter/jupyterIntegration.ts +++ b/src/client/jupyter/jupyterIntegration.ts @@ -63,7 +63,7 @@ type PythonApiForJupyterExtension = { /** * IInterpreterService */ - onDidChangeInterpreter: Event; + onDidChangeInterpreter: Event; /** * IInterpreterService */ diff --git a/src/test/linters/lint.provider.test.ts b/src/test/linters/lint.provider.test.ts index 680dfecc0277c..760c2282ba05b 100644 --- a/src/test/linters/lint.provider.test.ts +++ b/src/test/linters/lint.provider.test.ts @@ -24,6 +24,7 @@ import { IPersistentStateFactory, IPythonSettings, Product, + Resource, WORKSPACE_MEMENTO, } from '../../client/common/types'; import { createDeferred } from '../../client/common/utils/async'; @@ -171,12 +172,12 @@ suite('Linting - Provider', () => { }); test('Lint on change interpreters', async () => { - const e = new vscode.EventEmitter(); + const e = new vscode.EventEmitter(); interpreterService.setup((x) => x.onDidChangeInterpreter).returns(() => e.event); const linterProvider = new LinterProvider(serviceContainer); await linterProvider.activate(); - e.fire(); + e.fire(undefined); engine.verify((x) => x.lintOpenPythonFiles(), TypeMoq.Times.once()); });