Skip to content

Commit 8c5ecc6

Browse files
author
Kartik Raj
committed
s
1 parent 2e02515 commit 8c5ecc6

File tree

7 files changed

+44
-47
lines changed

7 files changed

+44
-47
lines changed

src/client/pythonEnvironments/base/locator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ export interface ILocator<I = PythonEnvInfo, E = PythonEnvsChangedEvent> extends
178178
* @param query - if provided, the locator will limit results to match
179179
* @returns - the fast async iterator of Python envs, which may have incomplete info
180180
*/
181-
iterEnvs(query?: QueryForEvent<E>, useWorkerThreads?: boolean): IPythonEnvsIterator<I>;
181+
iterEnvs(query?: QueryForEvent<E>): IPythonEnvsIterator<I>;
182182
}
183183

184184
export type ICompositeLocator<I = PythonEnvInfo, E = PythonEnvsChangedEvent> = Omit<ILocator<I, E>, 'providerId'>;

src/client/pythonEnvironments/base/locators/lowLevel/condaLocator.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { BasicEnvInfo, IPythonEnvsIterator } from '../../locator';
66
import { Conda, getCondaEnvironmentsTxt } from '../../../common/environmentManagers/conda';
77
import { traceError, traceVerbose } from '../../../../logging';
88
import { FSWatchingLocator } from './fsWatchingLocator';
9+
import { DiscoveryUsingWorkers } from '../../../../common/experiments/groups';
10+
import { inExperiment } from '../../../common/externalDependencies';
911

1012
export class CondaEnvironmentLocator extends FSWatchingLocator {
1113
public readonly providerId: string = 'conda-envs';
@@ -19,8 +21,11 @@ export class CondaEnvironmentLocator extends FSWatchingLocator {
1921
}
2022

2123
// eslint-disable-next-line class-methods-use-this
22-
public async *doIterEnvs(): IPythonEnvsIterator<BasicEnvInfo> {
23-
const conda = await Conda.getConda();
24+
public async *doIterEnvs(
25+
_: unknown,
26+
useWorkerThreads = inExperiment(DiscoveryUsingWorkers.experiment),
27+
): IPythonEnvsIterator<BasicEnvInfo> {
28+
const conda = await Conda.getConda(undefined, useWorkerThreads);
2429
if (conda === undefined) {
2530
traceVerbose(`Couldn't locate the conda binary.`);
2631
return;

src/client/pythonEnvironments/base/locators/lowLevel/windowsRegistryLocator.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@ import { BasicEnvInfo, IPythonEnvsIterator, Locator } from '../../locator';
77
import { getRegistryInterpreters } from '../../../common/windowsUtils';
88
import { traceError, traceVerbose } from '../../../../logging';
99
import { isMicrosoftStoreDir } from '../../../common/environmentManagers/microsoftStoreEnv';
10+
import { inExperiment } from '../../../common/externalDependencies';
11+
import { DiscoveryUsingWorkers } from '../../../../common/experiments/groups';
1012

1113
export class WindowsRegistryLocator extends Locator<BasicEnvInfo> {
1214
public readonly providerId: string = 'windows-registry';
1315

1416
// eslint-disable-next-line class-methods-use-this
15-
public iterEnvs(_?: unknown, useWorkerThreads = true): IPythonEnvsIterator<BasicEnvInfo> {
17+
public iterEnvs(
18+
_?: unknown,
19+
useWorkerThreads = inExperiment(DiscoveryUsingWorkers.experiment),
20+
): IPythonEnvsIterator<BasicEnvInfo> {
1621
const iterator = async function* () {
1722
traceVerbose('Searching for windows registry interpreters');
1823
const interpreters = await getRegistryInterpreters(useWorkerThreads);

src/client/pythonEnvironments/base/locators/wrappers.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33

44
// eslint-disable-next-line max-classes-per-file
55
import { Uri } from 'vscode';
6-
import { DiscoveryUsingWorkers } from '../../../common/experiments/groups';
76
import { IDisposable } from '../../../common/types';
87
import { iterEmpty } from '../../../common/utils/async';
98
import { getURIFilter } from '../../../common/utils/misc';
109
import { Disposables } from '../../../common/utils/resourceLifecycle';
11-
import { traceLog } from '../../../logging';
12-
import { inExperiment } from '../../common/externalDependencies';
1310
import { PythonEnvInfo } from '../info';
1411
import { BasicEnvInfo, ILocator, IPythonEnvsIterator, PythonLocatorQuery } from '../locator';
1512
import { combineIterators, Locators } from '../locators';
@@ -20,8 +17,6 @@ import { LazyResourceBasedLocator } from './common/resourceBasedLocator';
2017
*/
2118

2219
export class ExtensionLocators<I = PythonEnvInfo> extends Locators<I> {
23-
private readonly useWorkerThreads: boolean;
24-
2520
constructor(
2621
// These are expected to be low-level locators (e.g. system).
2722
private readonly nonWorkspace: ILocator<I>[],
@@ -30,10 +25,6 @@ export class ExtensionLocators<I = PythonEnvInfo> extends Locators<I> {
3025
private readonly workspace: ILocator<I>,
3126
) {
3227
super([...nonWorkspace, workspace]);
33-
this.useWorkerThreads = inExperiment(DiscoveryUsingWorkers.experiment);
34-
if (this.useWorkerThreads) {
35-
traceLog('Using worker threads for discovery...');
36-
}
3728
}
3829

3930
public iterEnvs(query?: PythonLocatorQuery): IPythonEnvsIterator<I> {
@@ -42,7 +33,7 @@ export class ExtensionLocators<I = PythonEnvInfo> extends Locators<I> {
4233
const nonWorkspace = query?.providerId
4334
? this.nonWorkspace.filter((locator) => query.providerId === locator.providerId)
4435
: this.nonWorkspace;
45-
iterators.push(...nonWorkspace.map((loc) => loc.iterEnvs(query, this.useWorkerThreads)));
36+
iterators.push(...nonWorkspace.map((loc) => loc.iterEnvs(query)));
4637
}
4738
return combineIterators(iterators);
4839
}

src/client/pythonEnvironments/common/environmentManagers/conda.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,16 +265,21 @@ export class Conda {
265265
* @param command - Command used to spawn conda. This has the same meaning as the
266266
* first argument of spawn() - i.e. it can be a full path, or just a binary name.
267267
*/
268-
constructor(readonly command: string, shellCommand?: string, private readonly shellPath?: string) {
268+
constructor(
269+
readonly command: string,
270+
shellCommand?: string,
271+
private readonly shellPath?: string,
272+
private readonly useWorkerThreads = true,
273+
) {
269274
this.shellCommand = shellCommand ?? command;
270275
onDidChangePythonSetting(CONDAPATH_SETTING_KEY, () => {
271276
Conda.condaPromise = new Map<string | undefined, Promise<Conda | undefined>>();
272277
});
273278
}
274279

275-
public static async getConda(shellPath?: string): Promise<Conda | undefined> {
280+
public static async getConda(shellPath?: string, useWorkerThreads?: boolean): Promise<Conda | undefined> {
276281
if (Conda.condaPromise.get(shellPath) === undefined || isTestExecution()) {
277-
Conda.condaPromise.set(shellPath, Conda.locate(shellPath));
282+
Conda.condaPromise.set(shellPath, Conda.locate(shellPath, useWorkerThreads));
278283
}
279284
return Conda.condaPromise.get(shellPath);
280285
}
@@ -285,10 +290,15 @@ export class Conda {
285290
*
286291
* @return A Conda instance corresponding to the binary, if successful; otherwise, undefined.
287292
*/
288-
private static async locate(shellPath?: string): Promise<Conda | undefined> {
293+
private static async locate(shellPath?: string, useWorkerThreads = true): Promise<Conda | undefined> {
289294
traceVerbose(`Searching for conda.`);
290295
const home = getUserHomeDir();
291-
const customCondaPath = getPythonSetting<string>(CONDAPATH_SETTING_KEY);
296+
let customCondaPath: string | undefined = 'conda';
297+
try {
298+
customCondaPath = getPythonSetting<string>(CONDAPATH_SETTING_KEY);
299+
} catch (ex) {
300+
traceError(`Failed to get conda path setting, ${ex}`);
301+
}
292302
const suffix = getOSType() === OSType.Windows ? 'Scripts\\conda.exe' : 'bin/conda';
293303

294304
// Produce a list of candidate binaries to be probed by exec'ing them.
@@ -307,7 +317,7 @@ export class Conda {
307317
}
308318

309319
async function* getCandidatesFromRegistry() {
310-
const interps = await getRegistryInterpreters(true);
320+
const interps = await getRegistryInterpreters(useWorkerThreads);
311321
const candidates = interps
312322
.filter((interp) => interp.interpreterPath && interp.distroOrgName === 'ContinuumAnalytics')
313323
.map((interp) => path.join(path.win32.dirname(interp.interpreterPath), suffix));
@@ -385,7 +395,7 @@ export class Conda {
385395
// Probe the candidates, and pick the first one that exists and does what we need.
386396
for await (const condaPath of getCandidates()) {
387397
traceVerbose(`Probing conda binary: ${condaPath}`);
388-
let conda = new Conda(condaPath, undefined, shellPath);
398+
let conda = new Conda(condaPath, undefined, shellPath, useWorkerThreads);
389399
try {
390400
await conda.getInfo();
391401
if (getOSType() === OSType.Windows && (isTestExecution() || condaPath !== customCondaPath)) {
@@ -440,7 +450,7 @@ export class Conda {
440450
if (shellPath) {
441451
options.shell = shellPath;
442452
}
443-
const resultPromise = exec(command, ['info', '--json'], options);
453+
const resultPromise = exec(command, ['info', '--json'], options, this.useWorkerThreads);
444454
// It has been observed that specifying a timeout is still not reliable to terminate the Conda process, see #27915.
445455
// Hence explicitly continue execution after timeout has been reached.
446456
const success = await Promise.race([

src/client/pythonEnvironments/common/externalDependencies.ts

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import * as fsapi from 'fs-extra';
55
import * as path from 'path';
6-
import { Worker } from 'worker_threads';
76
import * as vscode from 'vscode';
87
import { IWorkspaceService } from '../../common/application/types';
98
import { ExecutionResult, IProcessServiceFactory, ShellOptions, SpawnOptions } from '../../common/process/types';
@@ -12,6 +11,7 @@ import { chain, iterable } from '../../common/utils/async';
1211
import { getOSType, OSType } from '../../common/utils/platform';
1312
import { IServiceContainer } from '../../ioc/types';
1413
import { traceError, traceVerbose } from '../../logging';
14+
import { DiscoveryUsingWorkers } from '../../common/experiments/groups';
1515

1616
let internalServiceContainer: IServiceContainer;
1717
export function initializeExternalDependencies(serviceContainer: IServiceContainer): void {
@@ -21,12 +21,20 @@ export function initializeExternalDependencies(serviceContainer: IServiceContain
2121
// processes
2222

2323
export async function shellExecute(command: string, options: ShellOptions = {}): Promise<ExecutionResult<string>> {
24+
const useWorker = inExperiment(DiscoveryUsingWorkers.experiment);
2425
const service = await internalServiceContainer.get<IProcessServiceFactory>(IProcessServiceFactory).create();
26+
options = { ...options, useWorker };
2527
return service.shellExec(command, options);
2628
}
2729

28-
export async function exec(file: string, args: string[], options: SpawnOptions = {}): Promise<ExecutionResult<string>> {
30+
export async function exec(
31+
file: string,
32+
args: string[],
33+
options: SpawnOptions = {},
34+
useWorker = inExperiment(DiscoveryUsingWorkers.experiment),
35+
): Promise<ExecutionResult<string>> {
2936
const service = await internalServiceContainer.get<IProcessServiceFactory>(IProcessServiceFactory).create();
37+
options = { ...options, useWorker };
3038
return service.exec(file, args, options);
3139
}
3240

@@ -201,25 +209,3 @@ export function onDidChangePythonSetting(name: string, callback: () => void, roo
201209
}
202210
});
203211
}
204-
205-
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
206-
export async function executeWorkerFile(workerFileName: string, workerData: any): Promise<any> {
207-
return new Promise((resolve, reject) => {
208-
const worker = new Worker(workerFileName, { workerData });
209-
worker.on('message', (res: { err: Error; res: unknown }) => {
210-
if (res.err) {
211-
reject(res.err);
212-
}
213-
resolve(res.res);
214-
});
215-
worker.on('error', (ex: Error) => {
216-
traceError(`Error in worker ${workerFileName}`, ex);
217-
reject(ex);
218-
});
219-
worker.on('exit', (code) => {
220-
if (code !== 0) {
221-
reject(new Error(`Worker ${workerFileName} stopped with exit code ${code}`));
222-
}
223-
});
224-
});
225-
}

src/client/pythonEnvironments/common/windowsRegistry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import { HKCU, HKLM, Options, REG_SZ, Registry, RegistryItem } from 'winreg';
66
import * as path from 'path';
77
import { createDeferred } from '../../common/utils/async';
8-
import { executeWorkerFile } from './externalDependencies';
8+
import { executeWorkerFile } from '../../common/process/worker/main';
99

1010
export { HKCU, HKLM, REG_SZ, Options };
1111

0 commit comments

Comments
 (0)