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
2 changes: 1 addition & 1 deletion src/client/common/installer/pipEnvInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { inject, injectable } from 'inversify';
import { IInterpreterLocatorService, IInterpreterService, PIPENV_SERVICE } from '../../interpreter/contracts';
import { IServiceContainer } from '../../ioc/types';
import { isPipenvEnvironmentRelatedToFolder } from '../../pythonEnvironments/discovery/locators/services/pipEnvHelper';
import { isPipenvEnvironmentRelatedToFolder } from '../../pythonEnvironments/common/environmentManagers/pipenv';
import { EnvironmentType, ModuleInstallerType } from '../../pythonEnvironments/info';
import { IWorkspaceService } from '../application/types';
import { inDiscoveryExperiment } from '../experiments/helpers';
Expand Down
2 changes: 1 addition & 1 deletion src/client/common/installer/poetryInstaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as path from 'path';
import { Uri } from 'vscode';
import { IInterpreterService } from '../../interpreter/contracts';
import { IServiceContainer } from '../../ioc/types';
import { isPoetryEnvironmentRelatedToFolder } from '../../pythonEnvironments/discovery/locators/services/poetry';
import { isPoetryEnvironmentRelatedToFolder } from '../../pythonEnvironments/common/environmentManagers/poetry';
import { EnvironmentType, ModuleInstallerType } from '../../pythonEnvironments/info';
import { IWorkspaceService } from '../application/types';
import { inDiscoveryExperiment } from '../experiments/helpers';
Expand Down
2 changes: 1 addition & 1 deletion src/client/common/process/pythonEnvironment.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 { CondaEnvironmentInfo } from '../../pythonEnvironments/discovery/locators/services/conda';
import { CondaEnvironmentInfo } from '../../pythonEnvironments/common/environmentManagers/conda';
import { buildPythonExecInfo, PythonExecInfo } from '../../pythonEnvironments/exec';
import { InterpreterInformation } from '../../pythonEnvironments/info';
import { getExecutablePath } from '../../pythonEnvironments/info/executable';
Expand Down
2 changes: 1 addition & 1 deletion src/client/common/process/pythonExecutionFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Uri } from 'vscode';
import { IEnvironmentActivationService } from '../../interpreter/activation/types';
import { IComponentAdapter, ICondaLocatorService, ICondaService } from '../../interpreter/contracts';
import { IServiceContainer } from '../../ioc/types';
import { CondaEnvironmentInfo } from '../../pythonEnvironments/discovery/locators/services/conda';
import { CondaEnvironmentInfo } from '../../pythonEnvironments/common/environmentManagers/conda';
import { inDiscoveryExperiment } from '../experiments/helpers';
import { sendTelemetryEvent } from '../../telemetry';
import { EventName } from '../../telemetry/constants';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { inject, injectable, named } from 'inversify';
import { Uri } from 'vscode';
import '../../extensions';
import { IInterpreterService } from '../../../interpreter/contracts';
import { isPipenvEnvironmentRelatedToFolder } from '../../../pythonEnvironments/discovery/locators/services/pipEnvHelper';
import { isPipenvEnvironmentRelatedToFolder } from '../../../pythonEnvironments/common/environmentManagers/pipenv';
import { EnvironmentType } from '../../../pythonEnvironments/info';
import { IWorkspaceService } from '../../application/types';
import { inDiscoveryExperiment } from '../../experiments/helpers';
Expand Down
2 changes: 1 addition & 1 deletion src/client/interpreter/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CodeLensProvider, ConfigurationTarget, Disposable, Event, TextDocument,
import { IExtensionSingleActivationService } from '../activation/types';
import { Resource } from '../common/types';
import { PythonEnvSource } from '../pythonEnvironments/base/info';
import { CondaEnvironmentInfo, CondaInfo } from '../pythonEnvironments/discovery/locators/services/conda';
import { CondaEnvironmentInfo, CondaInfo } from '../pythonEnvironments/common/environmentManagers/conda';
import { EnvironmentType, PythonEnvironment } from '../pythonEnvironments/info';

export const INTERPRETER_LOCATOR_SERVICE = 'IInterpreterLocatorService';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { traceVerbose } from '../../common/logger';
import { IDisposableRegistry } from '../../common/types';
import { createDeferred, Deferred } from '../../common/utils/async';
import { createRunningWorkerPool, IWorkerPool, QueuePosition } from '../../common/utils/workerPool';
import { getInterpreterInfo, InterpreterInformation } from '../base/info/interpreter';
import { buildPythonExecInfo } from '../exec';
import { traceVerbose } from '../../../common/logger';
import { IDisposableRegistry } from '../../../common/types';
import { createDeferred, Deferred } from '../../../common/utils/async';
import { createRunningWorkerPool, IWorkerPool, QueuePosition } from '../../../common/utils/workerPool';
import { getInterpreterInfo, InterpreterInformation } from './interpreter';
import { buildPythonExecInfo } from '../../exec';

export enum EnvironmentInfoServiceQueuePriority {
Default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { cloneDeep } from 'lodash';
import { Event, EventEmitter } from 'vscode';
import { traceVerbose } from '../../../../common/logger';
import { identifyEnvironment } from '../../../common/environmentIdentifier';
import { IEnvironmentInfoService } from '../../../info/environmentInfoService';
import { IEnvironmentInfoService } from '../../info/environmentInfoService';
import { PythonEnvInfo } from '../../info';
import { getEnvDisplayString } from '../../info/env';
import { InterpreterInformation } from '../../info/interpreter';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import {
getPythonVersionFromPath,
} from '../../../common/commonUtils';
import { getFileInfo, getWorkspaceFolders, isParentPath } from '../../../common/externalDependencies';
import { AnacondaCompanyName, Conda } from '../../../discovery/locators/services/conda';
import { parsePyenvVersion } from '../../../discovery/locators/services/pyenvLocator';
import { AnacondaCompanyName, Conda } from '../../../common/environmentManagers/conda';
import { parsePyenvVersion } from '../../../common/environmentManagers/pyenv';
import { Architecture, getOSType, OSType } from '../../../../common/utils/platform';
import { getPythonVersionFromPath as parsePythonVersionFromPath, parseVersion } from '../../info/pythonVersion';
import { getRegistryInterpreters, getRegistryInterpretersSync } from '../../../common/windowsUtils';
Expand Down Expand Up @@ -169,7 +169,7 @@ async function resolvePyenvEnv(executablePath: string): Promise<PythonEnvInfo> {

// The sub-directory name sometimes can contain distro and python versions.
// here we attempt to extract the texts out of the name.
const versionStrings = await parsePyenvVersion(name);
const versionStrings = parsePyenvVersion(name);

const envInfo = buildEnvInfo({
kind: PythonEnvKind.Pyenv,
Expand Down
138 changes: 138 additions & 0 deletions src/client/pythonEnvironments/base/locators/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

// eslint-disable-next-line max-classes-per-file
import { Uri } from 'vscode';
import { iterEmpty } from '../../../common/utils/async';
import { getURIFilter } from '../../../common/utils/misc';
import { Disposables, IDisposable } from '../../../common/utils/resourceLifecycle';
import { PythonEnvInfo } from '../info';
import { ILocator, IPythonEnvsIterator, PythonLocatorQuery } from '../locator';
import { combineIterators, Locators } from '../locators';
import { LazyResourceBasedLocator } from './common/resourceBasedLocator';

/**
* A wrapper around all locators used by the extension.
*/

export class ExtensionLocators<I = PythonEnvInfo> extends Locators<I> {
constructor(
// These are expected to be low-level locators (e.g. system).
nonWorkspace: ILocator<I>[],
// This is expected to be a locator wrapping any found in
// the workspace (i.e. WorkspaceLocators).
workspace: ILocator<I>,
) {
super([...nonWorkspace, workspace]);
}
}
type WorkspaceLocatorFactoryResult<I> = ILocator<I> & Partial<IDisposable>;
type WorkspaceLocatorFactory<I = PythonEnvInfo> = (root: Uri) => WorkspaceLocatorFactoryResult<I>[];
type RootURI = string;

export type WatchRootsArgs = {
initRoot(root: Uri): void;
addRoot(root: Uri): void;
removeRoot(root: Uri): void;
};
type WatchRootsFunc = (args: WatchRootsArgs) => IDisposable;
// XXX Factor out RootedLocators and MultiRootedLocators.
/**
* The collection of all workspace-specific locators used by the extension.
*
* The factories are used to produce the locators for each workspace folder.
*/

export class WorkspaceLocators<I = PythonEnvInfo> extends LazyResourceBasedLocator<I> {
private readonly locators: Record<RootURI, [ILocator<I>, IDisposable]> = {};

private readonly roots: Record<RootURI, Uri> = {};

constructor(private readonly watchRoots: WatchRootsFunc, private readonly factories: WorkspaceLocatorFactory<I>[]) {
super();
}

public async dispose(): Promise<void> {
await super.dispose();

// Clear all the roots.
const roots = Object.keys(this.roots).map((key) => this.roots[key]);
roots.forEach((root) => this.removeRoot(root));
}

protected doIterEnvs(query?: PythonLocatorQuery): IPythonEnvsIterator<I> {
const iterators = Object.keys(this.locators).map((key) => {
if (query?.searchLocations !== undefined) {
const root = this.roots[key];
// Match any related search location.
const filter = getURIFilter(root, { checkParent: true, checkChild: true, checkExact: true });
// Ignore any requests for global envs.
if (!query.searchLocations.roots.some(filter)) {
// This workspace folder did not match the query, so skip it!
return iterEmpty<I>();
}
}
// The query matches or was not location-specific.
const [locator] = this.locators[key];
return locator.iterEnvs(query);
});
return combineIterators(iterators);
}

protected async initResources(): Promise<void> {
const disposable = this.watchRoots({
initRoot: (root: Uri) => this.addRoot(root),
addRoot: (root: Uri) => {
// Drop the old one, if necessary.
this.removeRoot(root);
this.addRoot(root);
this.emitter.fire({ searchLocation: root });
},
removeRoot: (root: Uri) => {
this.removeRoot(root);
this.emitter.fire({ searchLocation: root });
},
});
this.disposables.push(disposable);
}

private addRoot(root: Uri): void {
// Create the root's locator, wrapping each factory-generated locator.
const locators: ILocator<I>[] = [];
const disposables = new Disposables();
this.factories.forEach((create) => {
create(root).forEach((loc) => {
locators.push(loc);
if (loc.dispose !== undefined) {
disposables.push(loc as IDisposable);
}
});
});
const locator = new Locators(locators);
// Cache it.
const key = root.toString();
this.locators[key] = [locator, disposables];
this.roots[key] = root;
// Hook up the watchers.
disposables.push(
locator.onChanged((e) => {
if (e.searchLocation === undefined) {
e.searchLocation = root;
}
this.emitter.fire(e);
}),
);
}

private removeRoot(root: Uri): void {
const key = root.toString();
const found = this.locators[key];
if (found === undefined) {
return;
}
const [, disposables] = found;
delete this.locators[key];
delete this.roots[key];
disposables.dispose();
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import '../../../../common/extensions';
import { PythonEnvKind } from '../../../base/info';
import { BasicEnvInfo, IPythonEnvsIterator, Locator } from '../../../base/locator';
import { PythonEnvKind } from '../../info';
import { BasicEnvInfo, IPythonEnvsIterator, Locator } from '../../locator';
import { getInterpreterPathFromDir } from '../../../common/commonUtils';
import { Conda } from './conda';
import { Conda } from '../../../common/environmentManagers/conda';
import { traceError, traceVerbose } from '../../../../common/logger';

export class CondaEnvironmentLocator extends Locator<BasicEnvInfo> {
public constructor() {
super();
}

// eslint-disable-next-line class-methods-use-this
public async *iterEnvs(): IPythonEnvsIterator<BasicEnvInfo> {
const conda = await Conda.getConda();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ import * as path from 'path';
import { traceError, traceVerbose } from '../../../../common/logger';
import { chain, iterable } from '../../../../common/utils/async';
import { getUserHomeDir } from '../../../../common/utils/platform';
import { PythonEnvKind } from '../../../base/info';
import { BasicEnvInfo, IPythonEnvsIterator } from '../../../base/locator';
import { FSWatchingLocator } from '../../../base/locators/lowLevel/fsWatchingLocator';
import { PythonEnvKind } from '../../info';
import { BasicEnvInfo, IPythonEnvsIterator } from '../../locator';
import { FSWatchingLocator } from './fsWatchingLocator';
import { findInterpretersInDir, looksLikeBasicVirtualPython } from '../../../common/commonUtils';
import {
getPythonSetting,
onDidChangePythonSetting,
pathExists,
untildify,
} from '../../../common/externalDependencies';
import { isPipenvEnvironment } from './pipEnvHelper';
import { isPipenvEnvironment } from '../../../common/environmentManagers/pipenv';
import {
isVenvEnvironment,
isVirtualenvEnvironment,
isVirtualenvwrapperEnvironment,
} from './virtualEnvironmentIdentifier';
} from '../../../common/environmentManagers/simplevirtualenvs';
import '../../../../common/extensions';
import { asyncFilter } from '../../../../common/utils/arrayUtils';
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import * as path from 'path';
import { traceError, traceVerbose } from '../../../../common/logger';
import { chain, iterable } from '../../../../common/utils/async';
import { getEnvironmentVariable, getOSType, getUserHomeDir, OSType } from '../../../../common/utils/platform';
import { PythonEnvKind } from '../../../base/info';
import { BasicEnvInfo, IPythonEnvsIterator } from '../../../base/locator';
import { FSWatchingLocator } from '../../../base/locators/lowLevel/fsWatchingLocator';
import { PythonEnvKind } from '../../info';
import { BasicEnvInfo, IPythonEnvsIterator } from '../../locator';
import { FSWatchingLocator } from './fsWatchingLocator';
import { findInterpretersInDir, looksLikeBasicVirtualPython } from '../../../common/commonUtils';
import { pathExists, untildify } from '../../../common/externalDependencies';
import { isPipenvEnvironment } from './pipEnvHelper';
import { isPipenvEnvironment } from '../../../common/environmentManagers/pipenv';
import {
isVenvEnvironment,
isVirtualenvEnvironment,
isVirtualenvwrapperEnvironment,
} from './virtualEnvironmentIdentifier';
} from '../../../common/environmentManagers/simplevirtualenvs';
import '../../../../common/extensions';
import { asyncFilter } from '../../../../common/utils/arrayUtils';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import * as path from 'path';
import { traceError, traceVerbose } from '../../../../common/logger';
import { chain, iterable } from '../../../../common/utils/async';
import { PythonEnvKind } from '../../../base/info';
import { BasicEnvInfo, IPythonEnvsIterator } from '../../../base/locator';
import { FSWatchingLocator } from '../../../base/locators/lowLevel/fsWatchingLocator';
import { PythonEnvKind } from '../../info';
import { BasicEnvInfo, IPythonEnvsIterator } from '../../locator';
import { FSWatchingLocator } from './fsWatchingLocator';
import { getInterpreterPathFromDir } from '../../../common/commonUtils';
import { pathExists } from '../../../common/externalDependencies';
import { isPoetryEnvironment, localPoetryEnvDirName, Poetry } from './poetry';
import { isPoetryEnvironment, localPoetryEnvDirName, Poetry } from '../../../common/environmentManagers/poetry';
import '../../../../common/extensions';
import { asyncFilter } from '../../../../common/utils/arrayUtils';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// Licensed under the MIT License.

import { traceError } from '../../../../common/logger';
import { PythonEnvKind, PythonEnvSource } from '../../../base/info';
import { BasicEnvInfo, IPythonEnvsIterator, Locator } from '../../../base/locator';
import { PythonEnvKind, PythonEnvSource } from '../../info';
import { BasicEnvInfo, IPythonEnvsIterator, Locator } from '../../locator';
import { commonPosixBinPaths, getPythonBinFromPosixPaths } from '../../../common/posixUtils';
import { isPyenvShimDir } from './pyenvLocator';
import { isPyenvShimDir } from '../../../common/environmentManagers/pyenv';

export class PosixKnownPathsLocator extends Locator<BasicEnvInfo> {
private kind: PythonEnvKind = PythonEnvKind.OtherGlobal;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import * as path from 'path';
import { traceError } from '../../../../common/logger';
import { PythonEnvKind } from '../../info';
import { BasicEnvInfo, IPythonEnvsIterator } from '../../locator';
import { FSWatchingLocator } from './fsWatchingLocator';
import { getInterpreterPathFromDir } from '../../../common/commonUtils';
import { getSubDirs } from '../../../common/externalDependencies';
import { getPyenvDir } from '../../../common/environmentManagers/pyenv';

function getPyenvVersionsDir(): string {
return path.join(getPyenvDir(), 'versions');
}

/**
* Gets all the pyenv environments.
*
* Remarks: This function looks at the <pyenv dir>/versions directory and gets
* all the environments (global or virtual) in that directory.
*/
async function* getPyenvEnvironments(): AsyncIterableIterator<BasicEnvInfo> {
const pyenvVersionDir = getPyenvVersionsDir();

const subDirs = getSubDirs(pyenvVersionDir, { resolveSymlinks: true });
for await (const subDirPath of subDirs) {
const interpreterPath = await getInterpreterPathFromDir(subDirPath);

if (interpreterPath) {
try {
yield {
kind: PythonEnvKind.Pyenv,
executablePath: interpreterPath,
};
} catch (ex) {
traceError(`Failed to process environment: ${interpreterPath}`, ex);
}
}
}
}

export class PyenvLocator extends FSWatchingLocator<BasicEnvInfo> {
constructor() {
super(getPyenvVersionsDir, async () => PythonEnvKind.Pyenv);
}

// eslint-disable-next-line class-methods-use-this
public doIterEnvs(): IPythonEnvsIterator<BasicEnvInfo> {
return getPyenvEnvironments();
}
}
Loading