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

This file was deleted.

1 change: 0 additions & 1 deletion src/client/application/diagnostics/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
export enum DiagnosticCodes {
InvalidEnvironmentPathVariableDiagnostic = 'InvalidEnvironmentPathVariableDiagnostic',
InvalidDebuggerTypeDiagnostic = 'InvalidDebuggerTypeDiagnostic',
InvalidPythonPathInDebuggerDiagnostic = 'InvalidPythonPathInDebuggerDiagnostic',
NoPythonInterpretersDiagnostic = 'NoPythonInterpretersDiagnostic',
MacInterpreterSelectedAndNoOtherInterpretersDiagnostic = 'MacInterpreterSelectedAndNoOtherInterpretersDiagnostic',
MacInterpreterSelectedAndHaveOtherInterpretersDiagnostic = 'MacInterpreterSelectedAndHaveOtherInterpretersDiagnostic'
Expand Down
2 changes: 0 additions & 2 deletions src/client/application/diagnostics/serviceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import { IServiceManager } from '../../ioc/types';
import { EnvironmentPathVariableDiagnosticsService, EnvironmentPathVariableDiagnosticsServiceId } from './checks/envPathVariable';
import { InvalidDebuggerTypeDiagnosticsService, InvalidDebuggerTypeDiagnosticsServiceId } from './checks/invalidDebuggerType';
import { InvalidPythonPathInDebuggerService, InvalidPythonPathInDebuggerServiceId } from './checks/invalidPythonPathInDebugger';
import { InvalidPythonInterpreterService, InvalidPythonInterpreterServiceId } from './checks/pythonInterpreter';
import { DiagnosticsCommandFactory } from './commands/factory';
import { IDiagnosticsCommandFactory } from './commands/types';
Expand All @@ -19,7 +18,6 @@ export function registerTypes(serviceManager: IServiceManager) {
serviceManager.addSingleton<IDiagnosticHandlerService<MessageCommandPrompt>>(IDiagnosticHandlerService, DiagnosticCommandPromptHandlerService, DiagnosticCommandPromptHandlerServiceId);
serviceManager.addSingleton<IDiagnosticsService>(IDiagnosticsService, EnvironmentPathVariableDiagnosticsService, EnvironmentPathVariableDiagnosticsServiceId);
serviceManager.addSingleton<IDiagnosticsService>(IDiagnosticsService, InvalidDebuggerTypeDiagnosticsService, InvalidDebuggerTypeDiagnosticsServiceId);
serviceManager.addSingleton<IDiagnosticsService>(IDiagnosticsService, InvalidPythonPathInDebuggerService, InvalidPythonPathInDebuggerServiceId);
serviceManager.addSingleton<IDiagnosticsService>(IDiagnosticsService, InvalidPythonInterpreterService, InvalidPythonInterpreterServiceId);
serviceManager.addSingleton<IDiagnosticsCommandFactory>(IDiagnosticsCommandFactory, DiagnosticsCommandFactory);
}
18 changes: 18 additions & 0 deletions src/client/debugger/Common/processServiceFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

'use strict';

import { inject, injectable } from 'inversify';
import { ProcessService } from '../../common/process/proc';
import { IBufferDecoder, IProcessService, IProcessServiceFactory } from '../../common/process/types';
import { IServiceContainer } from '../../ioc/types';

@injectable()
export class DebuggerProcessServiceFactory implements IProcessServiceFactory {
constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { }
public create(): Promise<IProcessService> {
const processService = new ProcessService(this.serviceContainer.get<IBufferDecoder>(IBufferDecoder), process.env);
return Promise.resolve(processService);
}
}
8 changes: 0 additions & 8 deletions src/client/debugger/configProviders/baseProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import { injectable, unmanaged } from 'inversify';
import * as path from 'path';
import { CancellationToken, DebugConfiguration, DebugConfigurationProvider, Uri, WorkspaceFolder } from 'vscode';
import { InvalidPythonPathInDebuggerServiceId } from '../../application/diagnostics/checks/invalidPythonPathInDebugger';
import { IDiagnosticsService, IInvalidPythonPathInDebuggerService } from '../../application/diagnostics/types';
import { IDocumentManager, IWorkspaceService } from '../../common/application/types';
import { PYTHON_LANGUAGE } from '../../common/constants';
import { IConfigurationService } from '../../common/types';
Expand All @@ -29,12 +27,6 @@ export abstract class BaseConfigurationProvider<L extends BaseLaunchRequestArgum
await this.provideAttachDefaults(workspaceFolder, debugConfiguration as PythonAttachDebugConfiguration<A>);
} else {
const config = debugConfiguration as PythonLaunchDebugConfiguration<L>;
const diagnosticService = this.serviceContainer.get<IInvalidPythonPathInDebuggerService>(IDiagnosticsService, InvalidPythonPathInDebuggerServiceId);
if (!await diagnosticService.validatePythonPath(config.pythonPath, workspaceFolder)) {
// Returning an invalid configuration will cause VSC to display `launch.json` and stop launching the debugger..
// tslint:disable-next-line:no-any
return {} as any;
}
const numberOfSettings = Object.keys(config);

if ((config.noDebug === true && numberOfSettings.length === 1) || numberOfSettings.length === 0) {
Expand Down
27 changes: 24 additions & 3 deletions src/client/debugger/mainV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { createDeferred, Deferred, sleep } from '../../utils/async';
import { noop } from '../../utils/misc';
import { isNotInstalledError } from '../common/helpers';
import { IFileSystem } from '../common/platform/types';
import { IProcessServiceFactory } from '../common/process/types';
import { ICurrentProcess } from '../common/types';
import { IServiceContainer } from '../ioc/types';
import { AttachRequestArguments, LaunchRequestArguments } from './Common/Contracts';
Expand All @@ -33,6 +34,7 @@ const killProcessTree = require('tree-kill');

const DEBUGGER_CONNECT_TIMEOUT = 20000;
const MIN_DEBUGGER_CONNECT_TIMEOUT = 5000;
const InvalidPythonPathInDebuggerMessage = 'You need to select a Python interpreter before you start debugging. \nTip: click on "Select Python Environment" in the status bar.';

/**
* Primary purpose of this class is to perform the handshake with VS Code and launch PTVSD process.
Expand Down Expand Up @@ -106,14 +108,33 @@ export class PythonDebugger extends DebugSession {
if ((typeof args.module !== 'string' || args.module.length === 0) && args.program && !fs.fileExistsSync(args.program)) {
return this.sendErrorResponse(response, { format: `File does not exist. "${args.program}"`, id: 1 }, undefined, undefined, ErrorDestination.User);
}
this.launchPTVSD(args)
.then(() => this.waitForPTVSDToConnect(args))
.then(() => this.emit('debugger_launched'))

this.validatePythonPath(response, args)
.then<any>(valid => {
if (!valid) {
return;
}
return this.launchPTVSD(args)
.then(() => this.waitForPTVSDToConnect(args))
.then(() => this.emit('debugger_launched'));
})
.catch(ex => {
const message = this.getUserFriendlyLaunchErrorMessage(args, ex) || 'Debug Error';
this.sendErrorResponse(response, { format: message, id: 1 }, undefined, undefined, ErrorDestination.User);
});
}
private async validatePythonPath(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): Promise<boolean> {
const pythonPath = typeof args.pythonPath === 'string' && args.pythonPath.length > 0 ? args.pythonPath : 'python';
const processFactory = this.serviceContainer.get<IProcessServiceFactory>(IProcessServiceFactory);
const processService = await processFactory.create();
const valid = await processService.exec(pythonPath, ['--version'])
.then(output => output.stdout.trim().length > 0)
.catch(() => false);
if (!valid) {
this.sendErrorResponse(response, { format: InvalidPythonPathInDebuggerMessage, id: 2 }, undefined, undefined, ErrorDestination.User);
}
return valid;
}
private async launchPTVSD(args: LaunchRequestArguments) {
const launcher = CreateLaunchDebugClient(args, this, this.supportsRunInTerminalRequest);
this.debugServer = launcher.CreateDebugServer(undefined, this.serviceContainer);
Expand Down
5 changes: 5 additions & 0 deletions src/client/debugger/serviceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import { FileSystem } from '../common/platform/fileSystem';
import { PlatformService } from '../common/platform/platformService';
import { IFileSystem, IPlatformService } from '../common/platform/types';
import { CurrentProcess } from '../common/process/currentProcess';
import { BufferDecoder } from '../common/process/decoder';
import { IBufferDecoder, IProcessServiceFactory } from '../common/process/types';
import { ICurrentProcess, ISocketServer } from '../common/types';
import { ServiceContainer } from '../ioc/container';
import { ServiceManager } from '../ioc/serviceManager';
import { IServiceContainer, IServiceManager } from '../ioc/types';
import { DebuggerBanner } from './banner';
import { DebugStreamProvider } from './Common/debugStreamProvider';
import { DebuggerProcessServiceFactory } from './Common/processServiceFactory';
import { ProtocolLogger } from './Common/protocolLogger';
import { ProtocolParser } from './Common/protocolParser';
import { ProtocolMessageWriter } from './Common/protocolWriter';
Expand All @@ -38,6 +41,8 @@ function registerDebuggerTypes(serviceManager: IServiceManager) {
serviceManager.addSingleton<IPlatformService>(IPlatformService, PlatformService);
serviceManager.addSingleton<ISocketServer>(ISocketServer, SocketServer);
serviceManager.addSingleton<IProtocolMessageWriter>(IProtocolMessageWriter, ProtocolMessageWriter);
serviceManager.addSingleton<IBufferDecoder>(IBufferDecoder, BufferDecoder);
serviceManager.addSingleton<IProcessServiceFactory>(IProcessServiceFactory, DebuggerProcessServiceFactory);
}

export function registerTypes(serviceManager: IServiceManager) {
Expand Down
17 changes: 5 additions & 12 deletions src/client/interpreter/locators/services/currentPathService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { IProcessServiceFactory } from '../../../common/process/types';
import { IConfigurationService } from '../../../common/types';
import { IServiceContainer } from '../../../ioc/types';
import { IInterpreterHelper, InterpreterType, PythonInterpreter } from '../../contracts';
import { IVirtualEnvironmentManager } from '../../virtualEnvs/types';
import { CacheableLocatorService } from './cacheableLocatorService';

/**
Expand All @@ -20,7 +19,6 @@ export class CurrentPathService extends CacheableLocatorService {
private readonly fs: IFileSystem;

public constructor(
@inject(IVirtualEnvironmentManager) private virtualEnvMgr: IVirtualEnvironmentManager,
@inject(IInterpreterHelper) private helper: IInterpreterHelper,
@inject(IProcessServiceFactory) private readonly processServiceFactory: IProcessServiceFactory,
@inject(IServiceContainer) serviceContainer: IServiceContainer
Expand Down Expand Up @@ -60,28 +58,23 @@ export class CurrentPathService extends CacheableLocatorService {
.then(listOfInterpreters => _.flatten(listOfInterpreters))
.then(interpreters => interpreters.filter(item => item.length > 0))
// tslint:disable-next-line:promise-function-async
.then(interpreters => Promise.all(interpreters.map(interpreter => this.getInterpreterDetails(interpreter, resource))))
.then(interpreters => Promise.all(interpreters.map(interpreter => this.getInterpreterDetails(interpreter))))
.then(interpreters => interpreters.filter(item => !!item).map(item => item!));
}

/**
* Return the information about the identified interpreter binary.
*/
private async getInterpreterDetails(interpreter: string, resource?: Uri): Promise<PythonInterpreter | undefined> {
return Promise.all([
this.helper.getInterpreterInformation(interpreter),
this.virtualEnvMgr.getEnvironmentName(interpreter, resource),
this.virtualEnvMgr.getEnvironmentType(interpreter, resource)
]).
then(([details, virtualEnvName, type]) => {
private async getInterpreterDetails(interpreter: string): Promise<PythonInterpreter | undefined> {
return this.helper.getInterpreterInformation(interpreter)
.then(details => {
if (!details) {
return;
}
return {
...(details as PythonInterpreter),
envName: virtualEnvName,
path: interpreter,
type: type ? type : InterpreterType.Unknown
type: details.type ? details.type : InterpreterType.Unknown
};
});
}
Expand Down
Loading