Skip to content

Commit 1f2ede2

Browse files
authored
fix: ensure env managers are using workspace persistent state (#455)
1 parent e5ac660 commit 1f2ede2

File tree

7 files changed

+49
-68
lines changed

7 files changed

+49
-68
lines changed

src/common/persistentState.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ExtensionContext, Memento } from 'vscode';
2-
import { createDeferred, Deferred } from './utils/deferred';
32
import { traceError } from './logging';
3+
import { createDeferred, Deferred } from './utils/deferred';
44

55
export interface PersistentState {
66
get<T>(key: string, defaultValue?: T): Promise<T | undefined>;
@@ -9,7 +9,6 @@ export interface PersistentState {
99
}
1010

1111
class PersistentStateImpl implements PersistentState {
12-
private keys: string[] = [];
1312
private clearing: Deferred<void>;
1413
constructor(private readonly momento: Memento) {
1514
this.clearing = createDeferred<void>();
@@ -24,10 +23,6 @@ class PersistentStateImpl implements PersistentState {
2423
}
2524
async set<T>(key: string, value: T): Promise<void> {
2625
await this.clearing.promise;
27-
28-
if (!this.keys.includes(key)) {
29-
this.keys.push(key);
30-
}
3126
await this.momento.update(key, value);
3227

3328
const before = JSON.stringify(value);
@@ -40,9 +35,8 @@ class PersistentStateImpl implements PersistentState {
4035
async clear(keys?: string[]): Promise<void> {
4136
if (this.clearing.completed) {
4237
this.clearing = createDeferred<void>();
43-
const _keys = keys ?? this.keys;
38+
const _keys = keys ?? this.momento.keys();
4439
await Promise.all(_keys.map((key) => this.momento.update(key, undefined)));
45-
this.keys = this.keys.filter((k) => _keys.includes(k));
4640
this.clearing.resolve();
4741
}
4842
return this.clearing.promise;
@@ -64,3 +58,9 @@ export function getWorkspacePersistentState(): Promise<PersistentState> {
6458
export function getGlobalPersistentState(): Promise<PersistentState> {
6559
return _global.promise;
6660
}
61+
62+
export async function clearPersistentState(): Promise<void> {
63+
const [workspace, global] = await Promise.all([_workspace.promise, _global.promise]);
64+
await Promise.all([workspace.clear(), global.clear()]);
65+
return undefined;
66+
}

src/extension.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { commands, ExtensionContext, LogOutputChannel, Terminal, Uri, window } f
22
import { PythonEnvironment, PythonEnvironmentApi, PythonProjectCreator } from './api';
33
import { ensureCorrectVersion } from './common/extVersion';
44
import { registerLogger, traceError, traceInfo } from './common/logging';
5-
import { setPersistentState } from './common/persistentState';
5+
import { clearPersistentState, setPersistentState } from './common/persistentState';
66
import { newProjectSelection } from './common/pickers/managers';
77
import { StopWatch } from './common/stopWatch';
88
import { EventNames } from './common/telemetry/constants';
@@ -15,6 +15,10 @@ import {
1515
onDidChangeActiveTerminal,
1616
onDidChangeTerminalShellIntegration,
1717
} from './common/window.apis';
18+
import { CreateQuickVirtualEnvironmentTool } from './features/chat/createQuickVenvTool';
19+
import { GetEnvironmentInfoTool } from './features/chat/getEnvInfoTool';
20+
import { GetExecutableTool } from './features/chat/getExecutableTool';
21+
import { InstallPackageTool } from './features/chat/installPackagesTool';
1822
import { createManagerReady } from './features/common/managerReady';
1923
import { AutoFindProjects } from './features/creators/autoFindProjects';
2024
import { ExistingProjects } from './features/creators/existingProjects';
@@ -211,6 +215,7 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
211215
await removePythonProject(item, projectManager);
212216
}),
213217
commands.registerCommand('python-envs.clearCache', async () => {
218+
await clearPersistentState();
214219
await envManagers.clearCache(undefined);
215220
await clearShellProfileCache(shellStartupProviders);
216221
}),

src/features/terminal/shells/pwsh/pwshStartup.ts

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { ShellScriptEditState, ShellSetupState, ShellStartupScriptProvider } fro
88
import { runCommand } from '../utils';
99

1010
import assert from 'assert';
11-
import { getGlobalPersistentState } from '../../../../common/persistentState';
11+
import { getWorkspacePersistentState } from '../../../../common/persistentState';
1212
import { ShellConstants } from '../../../common/shellConstants';
1313
import { hasStartupCode, insertStartupCode, removeStartupCode } from '../common/editUtils';
1414
import { extractProfilePath, PROFILE_TAG_END, PROFILE_TAG_START } from '../common/shellUtils';
@@ -18,25 +18,19 @@ const PWSH_PROFILE_PATH_CACHE_KEY = 'PWSH_PROFILE_PATH_CACHE';
1818
const PS5_PROFILE_PATH_CACHE_KEY = 'PS5_PROFILE_PATH_CACHE';
1919
let pwshProfilePath: string | undefined;
2020
let ps5ProfilePath: string | undefined;
21-
async function clearPwshCache(shell: 'powershell' | 'pwsh'): Promise<void> {
22-
const global = await getGlobalPersistentState();
23-
if (shell === 'powershell') {
24-
ps5ProfilePath = undefined;
25-
await global.clear([PS5_PROFILE_PATH_CACHE_KEY]);
26-
} else {
27-
pwshProfilePath = undefined;
28-
await global.clear([PWSH_PROFILE_PATH_CACHE_KEY]);
29-
}
21+
function clearPwshCache() {
22+
ps5ProfilePath = undefined;
23+
pwshProfilePath = undefined;
3024
}
3125

3226
async function setProfilePathCache(shell: 'powershell' | 'pwsh', profilePath: string): Promise<void> {
33-
const global = await getGlobalPersistentState();
27+
const state = await getWorkspacePersistentState();
3428
if (shell === 'powershell') {
3529
ps5ProfilePath = profilePath;
36-
await global.set(PS5_PROFILE_PATH_CACHE_KEY, profilePath);
30+
await state.set(PS5_PROFILE_PATH_CACHE_KEY, profilePath);
3731
} else {
3832
pwshProfilePath = profilePath;
39-
await global.set(PWSH_PROFILE_PATH_CACHE_KEY, profilePath);
33+
await state.set(PWSH_PROFILE_PATH_CACHE_KEY, profilePath);
4034
}
4135
}
4236

@@ -308,10 +302,7 @@ export class PwshStartupProvider implements ShellStartupScriptProvider {
308302
}
309303

310304
async clearCache(): Promise<void> {
311-
for (const shell of this._supportedShells) {
312-
await clearPwshCache(shell);
313-
}
314-
305+
clearPwshCache();
315306
// Reset installation check cache as well
316307
this._isPwshInstalled = undefined;
317308
this._isPs5Installed = undefined;

src/managers/conda/condaUtils.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { ENVS_EXTENSION_ID, EXTENSION_ROOT_DIR } from '../../common/constants';
2929
import { showErrorMessageWithLogs } from '../../common/errors/utils';
3030
import { Common, CondaStrings, PackageManagement, Pickers } from '../../common/localize';
3131
import { traceInfo } from '../../common/logging';
32-
import { getGlobalPersistentState, getWorkspacePersistentState } from '../../common/persistentState';
32+
import { getWorkspacePersistentState } from '../../common/persistentState';
3333
import { pickProject } from '../../common/pickers/projects';
3434
import { createDeferred } from '../../common/utils/deferred';
3535
import { untildify } from '../../common/utils/pathUtils';
@@ -62,10 +62,6 @@ export const CONDA_GLOBAL_KEY = `${ENVS_EXTENSION_ID}:conda:GLOBAL_SELECTED`;
6262

6363
let condaPath: string | undefined;
6464
export async function clearCondaCache(): Promise<void> {
65-
const state = await getWorkspacePersistentState();
66-
await state.clear([CONDA_PATH_KEY, CONDA_WORKSPACE_KEY, CONDA_GLOBAL_KEY]);
67-
const global = await getGlobalPersistentState();
68-
await global.clear([CONDA_PREFIXES_KEY]);
6965
condaPath = undefined;
7066
}
7167

@@ -245,7 +241,7 @@ async function getPrefixes(): Promise<string[]> {
245241
return prefixes;
246242
}
247243

248-
const state = await getGlobalPersistentState();
244+
const state = await getWorkspacePersistentState();
249245
prefixes = await state.get<string[]>(CONDA_PREFIXES_KEY);
250246
if (prefixes) {
251247
return prefixes;

src/managers/poetry/main.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,17 @@ export async function registerPoetryFeatures(
3636
return;
3737
}
3838
}
39-
}
4039

41-
const envManager = new PoetryManager(nativeFinder, api);
42-
const pkgManager = new PoetryPackageManager(api, outputChannel, envManager);
40+
const envManager = new PoetryManager(nativeFinder, api);
41+
const pkgManager = new PoetryPackageManager(api, outputChannel, envManager);
4342

44-
disposables.push(
45-
envManager,
46-
pkgManager,
47-
api.registerEnvironmentManager(envManager),
48-
api.registerPackageManager(pkgManager),
49-
);
43+
disposables.push(
44+
envManager,
45+
pkgManager,
46+
api.registerEnvironmentManager(envManager),
47+
api.registerPackageManager(pkgManager),
48+
);
49+
}
5050
} catch (ex) {
5151
traceInfo('Poetry not found, turning off poetry features.', ex);
5252
}

src/managers/poetry/poetryUtils.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from '../../api';
1212
import { ENVS_EXTENSION_ID } from '../../common/constants';
1313
import { traceError, traceInfo } from '../../common/logging';
14-
import { getGlobalPersistentState, getWorkspacePersistentState } from '../../common/persistentState';
14+
import { getWorkspacePersistentState } from '../../common/persistentState';
1515
import { getUserHomeDir, untildify } from '../../common/utils/pathUtils';
1616
import { isWindows } from '../../common/utils/platformUtils';
1717
import { ShellConstants } from '../../features/common/shellConstants';
@@ -43,36 +43,28 @@ let poetryPath: string | undefined;
4343
let poetryVirtualenvsPath: string | undefined;
4444

4545
export async function clearPoetryCache(): Promise<void> {
46-
// Clear workspace-specific settings
47-
const state = await getWorkspacePersistentState();
48-
await state.clear([POETRY_WORKSPACE_KEY]);
49-
50-
// Clear global settings
51-
const global = await getGlobalPersistentState();
52-
await global.clear([POETRY_PATH_KEY, POETRY_GLOBAL_KEY, POETRY_VIRTUALENVS_PATH_KEY]);
53-
5446
// Reset in-memory cache
5547
poetryPath = undefined;
5648
poetryVirtualenvsPath = undefined;
5749
}
5850

5951
async function setPoetry(poetry: string): Promise<void> {
6052
poetryPath = poetry;
61-
const global = await getGlobalPersistentState();
62-
await global.set(POETRY_PATH_KEY, poetry);
53+
const state = await getWorkspacePersistentState();
54+
await state.set(POETRY_PATH_KEY, poetry);
6355

6456
// Also get and cache the virtualenvs path
6557
await getPoetryVirtualenvsPath(poetry);
6658
}
6759

6860
export async function getPoetryForGlobal(): Promise<string | undefined> {
69-
const global = await getGlobalPersistentState();
70-
return await global.get(POETRY_GLOBAL_KEY);
61+
const state = await getWorkspacePersistentState();
62+
return await state.get(POETRY_GLOBAL_KEY);
7163
}
7264

7365
export async function setPoetryForGlobal(poetryPath: string | undefined): Promise<void> {
74-
const global = await getGlobalPersistentState();
75-
await global.set(POETRY_GLOBAL_KEY, poetryPath);
66+
const state = await getWorkspacePersistentState();
67+
await state.set(POETRY_GLOBAL_KEY, poetryPath);
7668
}
7769

7870
export async function getPoetryForWorkspace(fsPath: string): Promise<string | undefined> {
@@ -117,8 +109,8 @@ export async function getPoetry(native?: NativePythonFinder): Promise<string | u
117109
return poetryPath;
118110
}
119111

120-
const global = await getGlobalPersistentState();
121-
poetryPath = await global.get<string>(POETRY_PATH_KEY);
112+
const state = await getWorkspacePersistentState();
113+
poetryPath = await state.get<string>(POETRY_PATH_KEY);
122114
if (poetryPath) {
123115
traceInfo(`Using poetry from persistent state: ${poetryPath}`);
124116
// Also retrieve the virtualenvs path if we haven't already
@@ -174,8 +166,8 @@ export async function getPoetryVirtualenvsPath(poetryExe?: string): Promise<stri
174166
}
175167

176168
// Check if we have it in persistent state
177-
const global = await getGlobalPersistentState();
178-
poetryVirtualenvsPath = await global.get<string>(POETRY_VIRTUALENVS_PATH_KEY);
169+
const state = await getWorkspacePersistentState();
170+
poetryVirtualenvsPath = await state.get<string>(POETRY_VIRTUALENVS_PATH_KEY);
179171
if (poetryVirtualenvsPath) {
180172
return untildify(poetryVirtualenvsPath);
181173
}
@@ -199,7 +191,7 @@ export async function getPoetryVirtualenvsPath(poetryExe?: string): Promise<stri
199191
}
200192

201193
if (poetryVirtualenvsPath) {
202-
await global.set(POETRY_VIRTUALENVS_PATH_KEY, poetryVirtualenvsPath);
194+
await state.set(POETRY_VIRTUALENVS_PATH_KEY, poetryVirtualenvsPath);
203195
return poetryVirtualenvsPath;
204196
}
205197
}
@@ -212,7 +204,7 @@ export async function getPoetryVirtualenvsPath(poetryExe?: string): Promise<stri
212204
const home = getUserHomeDir();
213205
if (home) {
214206
poetryVirtualenvsPath = path.join(home, '.cache', 'pypoetry', 'virtualenvs');
215-
await global.set(POETRY_VIRTUALENVS_PATH_KEY, poetryVirtualenvsPath);
207+
await state.set(POETRY_VIRTUALENVS_PATH_KEY, poetryVirtualenvsPath);
216208
return poetryVirtualenvsPath;
217209
}
218210

src/managers/pyenv/pyenvUtils.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from '../../api';
1212
import { ENVS_EXTENSION_ID } from '../../common/constants';
1313
import { traceError, traceInfo } from '../../common/logging';
14-
import { getGlobalPersistentState, getWorkspacePersistentState } from '../../common/persistentState';
14+
import { getWorkspacePersistentState } from '../../common/persistentState';
1515
import { getUserHomeDir, normalizePath, untildify } from '../../common/utils/pathUtils';
1616
import { isWindows } from '../../common/utils/platformUtils';
1717
import {
@@ -40,10 +40,7 @@ export const PYENV_GLOBAL_KEY = `${ENVS_EXTENSION_ID}:pyenv:GLOBAL_SELECTED`;
4040

4141
let pyenvPath: string | undefined;
4242
export async function clearPyenvCache(): Promise<void> {
43-
const state = await getWorkspacePersistentState();
44-
await state.clear([PYENV_WORKSPACE_KEY, PYENV_GLOBAL_KEY]);
45-
const global = await getGlobalPersistentState();
46-
await global.clear([PYENV_PATH_KEY]);
43+
pyenvPath = undefined;
4744
}
4845

4946
async function setPyenv(pyenv: string): Promise<void> {
@@ -225,7 +222,7 @@ export async function refreshPyenv(
225222
.filter((e) => !isNativeEnvInfo(e))
226223
.map((e) => e as NativeEnvManagerInfo)
227224
.filter((e) => e.tool.toLowerCase() === 'pyenv');
228-
225+
229226
if (managers.length > 0) {
230227
pyenv = managers[0].executable;
231228
await setPyenv(pyenv);

0 commit comments

Comments
 (0)