Skip to content
Draft
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
14 changes: 0 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -578,20 +578,6 @@
"scope": "resource",
"type": "string"
},
"python.locator": {
"default": "js",
"description": "%python.locator.description%",
"enum": [
"js",
"native"
],
"tags": [
"onExP",
"preview"
],
"scope": "machine",
"type": "string"
},
"python.pipenvPath": {
"default": "pipenv",
"description": "%python.pipenvPath.description%",
Expand Down
1 change: 0 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
"python.logging.level.description": "The logging level the extension logs at, defaults to 'error'",
"python.logging.level.deprecation": "This setting is deprecated. Please use command `Developer: Set Log Level...` to set logging level.",
"python.missingPackage.severity.description": "Set severity of missing packages in requirements.txt or pyproject.toml",
"python.locator.description": "[Experimental] Select implementation of environment locators. This is an experimental setting while we test native environment location.",
"python.pipenvPath.description": "Path to the pipenv executable to use for activation.",
"python.poetryPath.description": "Path to the poetry executable.",
"python.pixiToolPath.description": "Path to the pixi executable.",
Expand Down
190 changes: 5 additions & 185 deletions src/client/pythonEnvironments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,22 @@
// Licensed under the MIT License.

import * as vscode from 'vscode';
import { Uri } from 'vscode';
import { cloneDeep } from 'lodash';
import { getGlobalStorage, IPersistentStorage } from '../common/persistentState';
import { getOSType, OSType } from '../common/utils/platform';
import { getGlobalStorage } from '../common/persistentState';
import { ActivationResult, ExtensionState } from '../components';
import { PythonEnvInfo } from './base/info';
import { BasicEnvInfo, IDiscoveryAPI, ILocator } from './base/locator';
import { PythonEnvsReducer } from './base/locators/composite/envsReducer';
import { PythonEnvsResolver } from './base/locators/composite/envsResolver';
import { WindowsPathEnvVarLocator } from './base/locators/lowLevel/windowsKnownPathsLocator';
import { WorkspaceVirtualEnvironmentLocator } from './base/locators/lowLevel/workspaceVirtualEnvLocator';
import { IDiscoveryAPI } from './base/locator';
import {
initializeExternalDependencies as initializeLegacyExternalDependencies,
normCasePath,
} from './common/externalDependencies';
import { ExtensionLocators, WatchRootsArgs, WorkspaceLocators } from './base/locators/wrappers';
import { CustomVirtualEnvironmentLocator } from './base/locators/lowLevel/customVirtualEnvLocator';
import { CondaEnvironmentLocator } from './base/locators/lowLevel/condaLocator';
import { GlobalVirtualEnvironmentLocator } from './base/locators/lowLevel/globalVirtualEnvronmentLocator';
import { PosixKnownPathsLocator } from './base/locators/lowLevel/posixKnownPathsLocator';
import { PyenvLocator } from './base/locators/lowLevel/pyenvLocator';
import { WindowsRegistryLocator } from './base/locators/lowLevel/windowsRegistryLocator';
import { MicrosoftStoreLocator } from './base/locators/lowLevel/microsoftStoreLocator';
import { getEnvironmentInfoService } from './base/info/environmentInfoService';
import { registerNewDiscoveryForIOC } from './legacyIOC';
import { PoetryLocator } from './base/locators/lowLevel/poetryLocator';
import { HatchLocator } from './base/locators/lowLevel/hatchLocator';
import { createPythonEnvironments } from './api';
import {
createCollectionCache as createCache,
IEnvsCollectionCache,
} from './base/locators/composite/envsCollectionCache';
import { EnvsCollectionService } from './base/locators/composite/envsCollectionService';
import { IDisposable } from '../common/types';
import { traceError } from '../logging';
import { ActiveStateLocator } from './base/locators/lowLevel/activeStateLocator';
import { CustomWorkspaceLocator } from './base/locators/lowLevel/customWorkspaceLocator';
import { PixiLocator } from './base/locators/lowLevel/pixiLocator';
import { getConfiguration } from '../common/vscodeApis/workspaceApis';
import { getNativePythonFinder } from './base/locators/common/nativePythonFinder';
import { createNativeEnvironmentsApi } from './nativeAPI';
import { useEnvExtension } from '../envExt/api.internal';
import { createEnvExtApi } from '../envExt/envExtApi';

const PYTHON_ENV_INFO_CACHE_KEY = 'PYTHON_ENV_INFO_CACHEv2';

export function shouldUseNativeLocator(): boolean {
const config = getConfiguration('python');
return config.get<string>('locator', 'js') === 'native';
}

/**
* Set up the Python environments component (during extension activation).'
*/
Expand All @@ -70,19 +35,9 @@ export async function initialize(ext: ExtensionState): Promise<IDiscoveryAPI> {
return api;
}

if (shouldUseNativeLocator()) {
const finder = getNativePythonFinder(ext.context);
const api = createNativeEnvironmentsApi(finder);
ext.disposables.push(api);
registerNewDiscoveryForIOC(
// These are what get wrapped in the legacy adapter.
ext.legacyIOC.serviceManager,
api,
);
return api;
}

const api = await createPythonEnvironments(() => createLocator(ext));
const finder = getNativePythonFinder(ext.context);
const api = createNativeEnvironmentsApi(finder);
ext.disposables.push(api);
registerNewDiscoveryForIOC(
// These are what get wrapped in the legacy adapter.
ext.legacyIOC.serviceManager,
Expand Down Expand Up @@ -136,138 +91,3 @@ export async function activate(api: IDiscoveryAPI, ext: ExtensionState): Promise
fullyReady: Promise.resolve(),
};
}

/**
* Get the locator to use in the component.
*/
async function createLocator(
ext: ExtensionState,
// This is shared.
): Promise<IDiscoveryAPI> {
// Create the low-level locators.
const locators: ILocator<BasicEnvInfo> = new ExtensionLocators<BasicEnvInfo>(
// Here we pull the locators together.
createNonWorkspaceLocators(ext),
createWorkspaceLocator(ext),
);

// Create the env info service used by ResolvingLocator and CachingLocator.
const envInfoService = getEnvironmentInfoService(ext.disposables);

// Build the stack of composite locators.
const reducer = new PythonEnvsReducer(locators);
const resolvingLocator = new PythonEnvsResolver(
reducer,
// These are shared.
envInfoService,
);
const caching = new EnvsCollectionService(
await createCollectionCache(ext),
// This is shared.
resolvingLocator,
shouldUseNativeLocator(),
);
return caching;
}

function createNonWorkspaceLocators(ext: ExtensionState): ILocator<BasicEnvInfo>[] {
const locators: (ILocator<BasicEnvInfo> & Partial<IDisposable>)[] = [];
locators.push(
// OS-independent locators go here.
new PyenvLocator(),
new CondaEnvironmentLocator(),
new ActiveStateLocator(),
new GlobalVirtualEnvironmentLocator(),
new CustomVirtualEnvironmentLocator(),
);

if (getOSType() === OSType.Windows) {
locators.push(
// Windows specific locators go here.
new WindowsRegistryLocator(),
new MicrosoftStoreLocator(),
new WindowsPathEnvVarLocator(),
);
} else {
locators.push(
// Linux/Mac locators go here.
new PosixKnownPathsLocator(),
);
}

const disposables = locators.filter((d) => d.dispose !== undefined) as IDisposable[];
ext.disposables.push(...disposables);
return locators;
}

function watchRoots(args: WatchRootsArgs): IDisposable {
const { initRoot, addRoot, removeRoot } = args;

const folders = vscode.workspace.workspaceFolders;
if (folders) {
folders.map((f) => f.uri).forEach(initRoot);
}

return vscode.workspace.onDidChangeWorkspaceFolders((event) => {
for (const root of event.removed) {
removeRoot(root.uri);
}
for (const root of event.added) {
addRoot(root.uri);
}
});
}

function createWorkspaceLocator(ext: ExtensionState): WorkspaceLocators {
const locators = new WorkspaceLocators(watchRoots, [
(root: vscode.Uri) => [
new WorkspaceVirtualEnvironmentLocator(root.fsPath),
new PoetryLocator(root.fsPath),
new HatchLocator(root.fsPath),
new PixiLocator(root.fsPath),
new CustomWorkspaceLocator(root.fsPath),
],
// Add an ILocator factory func here for each kind of workspace-rooted locator.
]);
ext.disposables.push(locators);
return locators;
}

function getFromStorage(storage: IPersistentStorage<PythonEnvInfo[]>): PythonEnvInfo[] {
return storage.get().map((e) => {
if (e.searchLocation) {
if (typeof e.searchLocation === 'string') {
e.searchLocation = Uri.parse(e.searchLocation);
} else if ('scheme' in e.searchLocation && 'path' in e.searchLocation) {
e.searchLocation = Uri.parse(`${e.searchLocation.scheme}://${e.searchLocation.path}`);
} else {
traceError('Unexpected search location', JSON.stringify(e.searchLocation));
}
}
return e;
});
}

function putIntoStorage(storage: IPersistentStorage<PythonEnvInfo[]>, envs: PythonEnvInfo[]): Promise<void> {
storage.set(
// We have to `cloneDeep()` here so that we don't overwrite the original `PythonEnvInfo` objects.
cloneDeep(envs).map((e) => {
if (e.searchLocation) {
// Make TS believe it is string. This is temporary. We need to serialize this in
// a custom way.
e.searchLocation = (e.searchLocation.toString() as unknown) as Uri;
}
return e;
}),
);
return Promise.resolve();
}

async function createCollectionCache(ext: ExtensionState): Promise<IEnvsCollectionCache> {
const storage = getGlobalStorage<PythonEnvInfo[]>(ext.context, PYTHON_ENV_INFO_CACHE_KEY, []);
const cache = await createCache({
get: () => getFromStorage(storage),
store: async (e) => putIntoStorage(storage, e),
});
return cache;
}
Loading