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
176 changes: 16 additions & 160 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { commands, ExtensionContext, extensions, LogOutputChannel, Terminal, Uri, window, workspace } from 'vscode';
import { commands, ExtensionContext, LogOutputChannel, Terminal, Uri, window } from 'vscode';
import { version as extensionVersion } from '../package.json';
import { PythonEnvironment, PythonEnvironmentApi, PythonProjectCreator } from './api';
import { ensureCorrectVersion } from './common/extVersion';
import { registerLogger, traceError, traceInfo, traceWarn } from './common/logging';
import { registerLogger, traceError, traceInfo, traceVerbose, traceWarn } from './common/logging';
import { clearPersistentState, setPersistentState } from './common/persistentState';
import { newProjectSelection } from './common/pickers/managers';
import { StopWatch } from './common/stopWatch';
import { EventNames } from './common/telemetry/constants';
import { sendManagerSelectionTelemetry } from './common/telemetry/helpers';
import { sendTelemetryEvent } from './common/telemetry/sender';
import { createDeferred } from './common/utils/deferred';
import { normalizePath } from './common/utils/pathUtils';
import { isWindows } from './common/utils/platformUtils';
import {
activeTerminal,
Expand Down Expand Up @@ -61,19 +61,23 @@ import { cleanupStartupScripts } from './features/terminal/shellStartupSetupHand
import { TerminalActivationImpl } from './features/terminal/terminalActivationState';
import { TerminalEnvVarInjector } from './features/terminal/terminalEnvVarInjector';
import { TerminalManager, TerminalManagerImpl } from './features/terminal/terminalManager';
import { getAutoActivationType, getEnvironmentForTerminal } from './features/terminal/utils';
import { getEnvironmentForTerminal } from './features/terminal/utils';
import { EnvManagerView } from './features/views/envManagersView';
import { ProjectView } from './features/views/projectView';
import { PythonStatusBarImpl } from './features/views/pythonStatusBar';
import { updateViewsAndStatus } from './features/views/revealHandler';
import { ProjectItem } from './features/views/treeViewItems';
import {
collectEnvironmentInfo,
getEnvManagerAndPackageManagerConfigLevels,
resolveDefaultInterpreter,
} from './helpers';
import { EnvironmentManagers, ProjectCreators, PythonProjectManager } from './internal.api';
import { registerSystemPythonFeatures } from './managers/builtin/main';
import { SysPythonManager } from './managers/builtin/sysPythonManager';
import {
createNativePythonFinder,
getNativePythonToolsPath,
NativeEnvInfo,
NativePythonFinder,
} from './managers/common/nativePythonFinder';
import { IDisposable } from './managers/common/types';
Expand All @@ -82,89 +86,6 @@ import { registerPipenvFeatures } from './managers/pipenv/main';
import { registerPoetryFeatures } from './managers/poetry/main';
import { registerPyenvFeatures } from './managers/pyenv/main';

/**
* Collects relevant Python environment information for issue reporting
*/
async function collectEnvironmentInfo(
context: ExtensionContext,
envManagers: EnvironmentManagers,
projectManager: PythonProjectManager,
): Promise<string> {
const info: string[] = [];

try {
// Extension version
const extensionVersion = context.extension?.packageJSON?.version || 'unknown';
info.push(`Extension Version: ${extensionVersion}`);

// Python extension version
const pythonExtension = extensions.getExtension('ms-python.python');
const pythonVersion = pythonExtension?.packageJSON?.version || 'not installed';
info.push(`Python Extension Version: ${pythonVersion}`);

// Environment managers
const managers = envManagers.managers;
info.push(`\nRegistered Environment Managers (${managers.length}):`);
managers.forEach((manager) => {
info.push(` - ${manager.id} (${manager.displayName})`);
});

// Available environments
const allEnvironments: PythonEnvironment[] = [];
for (const manager of managers) {
try {
const envs = await manager.getEnvironments('all');
allEnvironments.push(...envs);
} catch (err) {
info.push(` Error getting environments from ${manager.id}: ${err}`);
}
}

info.push(`\nTotal Available Environments: ${allEnvironments.length}`);
if (allEnvironments.length > 0) {
info.push('Environment Details:');
allEnvironments.slice(0, 10).forEach((env, index) => {
info.push(` ${index + 1}. ${env.displayName} (${env.version}) - ${env.displayPath}`);
});
if (allEnvironments.length > 10) {
info.push(` ... and ${allEnvironments.length - 10} more environments`);
}
}

// Python projects
const projects = projectManager.getProjects();
info.push(`\nPython Projects (${projects.length}):`);
for (let index = 0; index < projects.length; index++) {
const project = projects[index];
info.push(` ${index + 1}. ${project.uri.fsPath}`);
try {
const env = await envManagers.getEnvironment(project.uri);
if (env) {
info.push(` Environment: ${env.displayName}`);
}
} catch (err) {
info.push(` Error getting environment: ${err}`);
}
}

// Current settings (non-sensitive)
const config = workspace.getConfiguration('python-envs');
const pyConfig = workspace.getConfiguration('python');
info.push('\nExtension Settings:');
info.push(` Default Environment Manager: ${config.get('defaultEnvManager')}`);
info.push(` Default Package Manager: ${config.get('defaultPackageManager')}`);
const pyenvAct = config.get('terminal.autoActivationType', undefined);
const pythonAct = pyConfig.get('terminal.activateEnvironment', undefined);
info.push(
`Auto-activation is "${getAutoActivationType()}". Activation based on first 'py-env.terminal.autoActivationType' setting which is '${pyenvAct}' and 'python.terminal.activateEnvironment' if the first is undefined which is '${pythonAct}'.\n`,
);
} catch (err) {
info.push(`\nError collecting environment information: ${err}`);
}

return info.join('\n');
}

export async function activate(context: ExtensionContext): Promise<PythonEnvironmentApi | undefined> {
const useEnvironmentsExtension = getConfiguration('python').get<boolean>('useEnvironmentsExtension', true);
traceInfo(`Experiment Status: useEnvironmentsExtension setting set to ${useEnvironmentsExtension}`);
Expand All @@ -183,6 +104,13 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron

ensureCorrectVersion();

// log extension version
traceVerbose(`Python-envs extension version: ${extensionVersion}`);
// log settings
const configLevels = getEnvManagerAndPackageManagerConfigLevels();
traceInfo(`\n=== ${configLevels.section} ===`);
traceInfo(JSON.stringify(configLevels, null, 2));

// Setup the persistent state for the extension.
setPersistentState(context);

Expand Down Expand Up @@ -595,78 +523,6 @@ export async function disposeAll(disposables: IDisposable[]): Promise<void> {
);
}

/**
* Sets the default Python interpreter for the workspace if the user has not explicitly set 'defaultEnvManager' or it is set to venv.
* @param nativeFinder - used to resolve interpreter paths.
* @param envManagers - contains all registered managers.
* @param api - The PythonEnvironmentApi for environment resolution and setting.
*/
async function resolveDefaultInterpreter(
nativeFinder: NativePythonFinder,
envManagers: EnvironmentManagers,
api: PythonEnvironmentApi,
) {
const defaultInterpreterPath = getConfiguration('python').get<string>('defaultInterpreterPath');

if (defaultInterpreterPath) {
const config = getConfiguration('python-envs');
const inspect = config.inspect<string>('defaultEnvManager');
const userDefinedDefaultManager =
inspect?.workspaceFolderValue !== undefined ||
inspect?.workspaceValue !== undefined ||
inspect?.globalValue !== undefined;
if (!userDefinedDefaultManager) {
try {
const resolved: NativeEnvInfo = await nativeFinder.resolve(defaultInterpreterPath);
if (resolved && resolved.executable) {
if (normalizePath(resolved.executable) === normalizePath(defaultInterpreterPath)) {
// no action required, the path is already correct
return;
}
const resolvedEnv = await api.resolveEnvironment(Uri.file(resolved.executable));
traceInfo(`[resolveDefaultInterpreter] API resolved environment: ${JSON.stringify(resolvedEnv)}`);

let findEnvManager = envManagers.managers.find((m) => m.id === resolvedEnv?.envId.managerId);
if (!findEnvManager) {
findEnvManager = envManagers.managers.find((m) => m.id === 'ms-python.python:system');
}
if (resolvedEnv) {
const newEnv: PythonEnvironment = {
envId: {
id: resolvedEnv?.envId.id,
managerId: resolvedEnv?.envId.managerId ?? '',
},
name: 'defaultInterpreterPath: ' + (resolved.version ?? ''),
displayName: 'defaultInterpreterPath: ' + (resolved.version ?? ''),
version: resolved.version ?? '',
displayPath: defaultInterpreterPath ?? '',
environmentPath: defaultInterpreterPath ? Uri.file(defaultInterpreterPath) : Uri.file(''),
sysPrefix: resolved.arch ?? '',
execInfo: {
run: {
executable: defaultInterpreterPath ?? '',
},
},
};
if (workspace.workspaceFolders?.[0] && findEnvManager) {
traceInfo(
`[resolveDefaultInterpreter] Setting environment for workspace: ${workspace.workspaceFolders[0].uri.fsPath}`,
);
await api.setEnvironment(workspace.workspaceFolders[0].uri, newEnv);
}
}
} else {
traceWarn(
`[resolveDefaultInterpreter] NativeFinder did not resolve an executable for path: ${defaultInterpreterPath}`,
);
}
} catch (err) {
traceError(`[resolveDefaultInterpreter] Error resolving default interpreter: ${err}`);
}
}
}
}

export async function deactivate(context: ExtensionContext) {
await disposeAll(context.subscriptions);
context.subscriptions.length = 0; // Clear subscriptions to prevent memory leaks
Expand Down
Loading
Loading