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
1 change: 1 addition & 0 deletions news/1 Enhancements/1030.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a Pyramid debug configuration for the experimental debugger.
19 changes: 18 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"activationEvents": [
"onLanguage:python",
"onDebugResolve:python",
"onDebugResolve:pythonExperimental",
"onCommand:python.execInTerminal",
"onCommand:python.sortImports",
"onCommand:python.runtests",
Expand Down Expand Up @@ -831,6 +832,21 @@
"bikes.json"
]
}
},
{
"label": "Python Experimental: Pyramid",
"description": "%python.snippet.launch.pyramid.description%",
"body": {
"name": "Pyramid",
"type": "pythonExperimental",
"request": "launch",
"args": [
"^\"\\${workspaceFolder}/development.ini\""
],
"debugOptions": [
"Pyramid"
]
}
}
],
"configurationAttributes": {
Expand Down Expand Up @@ -884,7 +900,8 @@
"items": {
"type": "string",
"enum": [
"Sudo"
"Sudo",
"Pyramid"
]
},
"default": []
Expand Down
7 changes: 5 additions & 2 deletions src/client/common/platform/fileSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export class FileSystem implements IFileSystem {
public fileExistsAsync(filePath: string): Promise<boolean> {
return this.objectExistsAsync(filePath, (stats) => stats.isFile());
}
public fileExistsSync(filePath: string): boolean {
return fs.existsSync(filePath);
}
/**
* Reads the contents of the file using utf8 and returns the string contents.
* @param {string} filePath
Expand Down Expand Up @@ -79,9 +82,9 @@ export class FileSystem implements IFileSystem {
}

public appendFileSync(filename: string, data: {}, encoding: string): void;
public appendFileSync(filename: string, data: {}, options?: { encoding?: string; mode?: number; flag?: string; }): void;
public appendFileSync(filename: string, data: {}, options?: { encoding?: string; mode?: number; flag?: string }): void;
// tslint:disable-next-line:unified-signatures
public appendFileSync(filename: string, data: {}, options?: { encoding?: string; mode?: string; flag?: string; }): void;
public appendFileSync(filename: string, data: {}, options?: { encoding?: string; mode?: string; flag?: string }): void;
public appendFileSync(filename: string, data: {}, optionsOrEncoding: {}): void {
return fs.appendFileSync(filename, data, optionsOrEncoding);
}
Expand Down
5 changes: 3 additions & 2 deletions src/client/common/platform/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ export interface IFileSystem {
directorySeparatorChar: string;
objectExistsAsync(path: string, statCheck: (s: fs.Stats) => boolean): Promise<boolean>;
fileExistsAsync(path: string): Promise<boolean>;
fileExistsSync(path: string): boolean;
directoryExistsAsync(path: string): Promise<boolean>;
createDirectoryAsync(path: string): Promise<void>;
getSubDirectoriesAsync(rootDir: string): Promise<string[]>;
arePathsSame(path1: string, path2: string): boolean;
readFile(filePath: string): Promise<string>;
appendFileSync(filename: string, data: {}, encoding: string): void;
appendFileSync(filename: string, data: {}, options?: { encoding?: string; mode?: number; flag?: string; }): void;
appendFileSync(filename: string, data: {}, options?: { encoding?: string; mode?: number; flag?: string }): void;
// tslint:disable-next-line:unified-signatures
appendFileSync(filename: string, data: {}, options?: { encoding?: string; mode?: string; flag?: string; }): void;
appendFileSync(filename: string, data: {}, options?: { encoding?: string; mode?: string; flag?: string }): void;
getRealPathAsync(path: string): Promise<string>;
}
2 changes: 1 addition & 1 deletion src/client/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,5 @@ export interface IConfigurationService {
export const ISocketServer = Symbol('ISocketServer');
export interface ISocketServer extends Disposable {
readonly client: Promise<Socket>;
Start(options?: { port?: number, host?: string }): Promise<number>;
Start(options?: { port?: number; host?: string }): Promise<number>;
}
4 changes: 2 additions & 2 deletions src/client/debugger/Common/Contracts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// tslint:disable:interface-name member-access no-single-line-block-comment no-any no-stateless-class member-ordering prefer-method-signature
// tslint:disable:interface-name member-access no-single-line-block-comment no-any no-stateless-class member-ordering prefer-method-signature no-unnecessary-class

'use strict';
import { ChildProcess } from 'child_process';
Expand All @@ -8,7 +8,7 @@ import { DebugProtocol } from 'vscode-debugprotocol';
import { DebuggerPerformanceTelemetry, DebuggerTelemetry } from '../../telemetry/types';

export class TelemetryEvent extends OutputEvent {
body: {
body!: {
/** The category of output (such as: 'console', 'stdout', 'stderr', 'telemetry'). If not specified, 'console' is assumed. */
category: string;
/** The output to report. */
Expand Down
2 changes: 1 addition & 1 deletion src/client/debugger/Common/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { DebuggerPerformanceTelemetry } from '../../telemetry/types';
import { TelemetryEvent } from './Contracts';

type DebugAction = 'stepIn' | 'stepOut' | 'continue' | 'next' | 'launch';
type DebugPerformanceInformation = { action: DebugAction, timer: StopWatch };
type DebugPerformanceInformation = { action: DebugAction; timer: StopWatch };

const executionStack: DebugPerformanceInformation[] = [];

Expand Down
15 changes: 9 additions & 6 deletions src/client/debugger/DebugClients/LocalDebugClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as child_process from 'child_process';
import { ChildProcess } from 'child_process';
import { ChildProcess, spawn } from 'child_process';
import * as path from 'path';
import { DebugSession, OutputEvent } from 'vscode-debugadapter';
import { DebugProtocol } from 'vscode-debugprotocol';
Expand Down Expand Up @@ -31,8 +30,8 @@ enum DebugServerStatus {
}

export class LocalDebugClient extends DebugClient<LaunchRequestArguments> {
protected pyProc: child_process.ChildProcess | undefined;
protected pythonProcess: IPythonProcess;
protected pyProc: ChildProcess | undefined;
protected pythonProcess!: IPythonProcess;
protected debugServer: BaseDebugServer | undefined;
private get debugServerStatus(): DebugServerStatus {
if (this.debugServer && this.debugServer!.IsRunning) {
Expand Down Expand Up @@ -114,7 +113,7 @@ export class LocalDebugClient extends DebugClient<LaunchRequestArguments> {
break;
}
default: {
this.pyProc = child_process.spawn(pythonPath, args, { cwd: processCwd, env: environmentVariables });
this.pyProc = spawn(pythonPath, args, { cwd: processCwd, env: environmentVariables });
this.handleProcessOutput(this.pyProc!, reject);

// Here we wait for the application to connect to the socket server.
Expand Down Expand Up @@ -174,7 +173,11 @@ export class LocalDebugClient extends DebugClient<LaunchRequestArguments> {
if (typeof this.args.module === 'string' && this.args.module.length > 0) {
return [vsDebugOptions.join(','), '-m', this.args.module].concat(programArgs);
}
return [vsDebugOptions.join(','), this.args.program].concat(programArgs);
const args = [vsDebugOptions.join(',')];
if (this.args.program && this.args.program.length > 0) {
args.push(this.args.program);
}
return args.concat(programArgs);
}
private launchExternalTerminal(sudo: boolean, cwd: string, pythonPath: string, args: string[], env: {}) {
return new Promise((resolve, reject) => {
Expand Down
33 changes: 12 additions & 21 deletions src/client/debugger/Main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// tslint:disable:quotemark ordered-imports promise-must-complete member-ordering no-any prefer-template cyclomatic-complexity no-empty no-multiline-string one-line no-invalid-template-strings no-suspicious-comment no-var-self
// tslint:disable:quotemark ordered-imports promise-must-complete member-ordering no-any prefer-template cyclomatic-complexity no-empty no-multiline-string one-line no-invalid-template-strings no-suspicious-comment no-var-self no-duplicate-imports
"use strict";

// This line should always be right on top.
Expand All @@ -9,8 +9,7 @@ if ((Reflect as any).metadata === undefined) {
}
import * as fs from "fs";
import * as path from "path";
import { Handles, InitializedEvent, OutputEvent, Scope, Source, StackFrame, StoppedEvent, TerminatedEvent, Thread, Variable, LoggingDebugSession, logger, BreakpointEvent, Breakpoint } from "vscode-debugadapter";
import { ThreadEvent } from "vscode-debugadapter";
import { Handles, InitializedEvent, OutputEvent, Scope, Source, StackFrame, StoppedEvent, TerminatedEvent, Thread, Variable, LoggingDebugSession, logger, BreakpointEvent, Breakpoint, ThreadEvent } from "vscode-debugadapter";
import { DebugProtocol } from "vscode-debugprotocol";
import { DEBUGGER } from '../../client/telemetry/constants';
import { DebuggerTelemetry } from '../../client/telemetry/types';
Expand All @@ -23,7 +22,6 @@ import { DebugClient } from "./DebugClients/DebugClient";
import { CreateAttachDebugClient, CreateLaunchDebugClient } from "./DebugClients/DebugFactory";
import { BaseDebugServer } from "./DebugServers/BaseDebugServer";
import { PythonProcess } from "./PythonProcess";
import { IS_WINDOWS } from './Common/Utils';
import { sendPerformanceTelemetry, capturePerformanceTelemetry, PerformanceTelemetryCondition } from "./Common/telemetry";
import { LogLevel } from "vscode-debugadapter/lib/logger";

Expand All @@ -41,13 +39,13 @@ export class PythonDebugger extends LoggingDebugSession {
private registeredBreakpoints: Map<number, IPythonBreakpoint>;
private registeredBreakpointsByFileName: Map<string, IPythonBreakpoint[]>;
private debuggerLoaded: Promise<any>;
private debuggerLoadedPromiseResolve: () => void;
private debuggerLoadedPromiseResolve!: () => void;
private debugClient?: DebugClient<{}>;
private configurationDone: Promise<any>;
private configurationDone!: Promise<any>;
private configurationDonePromiseResolve?: () => void;
private lastException?: IPythonException;
private _supportsRunInTerminalRequest: boolean;
private terminateEventSent: boolean;
private _supportsRunInTerminalRequest: boolean = false;
private terminateEventSent: boolean = false;
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean) {
super(path.join(__dirname, '..', '..', '..', 'debug.log'), debuggerLinesStartAt1, isServer === true);
this._variableHandles = new Handles<IDebugVariable>();
Expand Down Expand Up @@ -92,7 +90,7 @@ export class PythonDebugger extends LoggingDebugSession {
}

private pythonProcess?: PythonProcess;
private debugServer: BaseDebugServer;
private debugServer!: BaseDebugServer;

private startDebugServer(): Promise<IDebugServer> {
let programDirectory = '';
Expand Down Expand Up @@ -208,8 +206,8 @@ export class PythonDebugger extends LoggingDebugSession {
this.sendEvent(new OutputEvent(output, outputChannel));
}
private entryResponse?: DebugProtocol.LaunchResponse;
private launchArgs: LaunchRequestArguments;
private attachArgs: AttachRequestArguments;
private launchArgs!: LaunchRequestArguments;
private attachArgs!: AttachRequestArguments;
private canStartDebugger(): Promise<boolean> {
return Promise.resolve(true);
}
Expand All @@ -230,15 +228,6 @@ export class PythonDebugger extends LoggingDebugSession {
}
catch (ex) {
}
if (Array.isArray(args.debugOptions) && args.debugOptions.indexOf("Pyramid") >= 0) {
const pserve = IS_WINDOWS ? "pserve.exe" : "pserve";
if (fs.existsSync(args.pythonPath)) {
args.program = path.join(path.dirname(args.pythonPath), pserve);
}
else {
args.program = pserve;
}
}
// Confirm the file exists
if (typeof args.module !== 'string' || args.module.length === 0) {
if (!fs.existsSync(args.program)) {
Expand Down Expand Up @@ -279,6 +268,7 @@ export class PythonDebugger extends LoggingDebugSession {
});

this.entryResponse = response;
// tslint:disable-next-line:no-this-assignment
const that = this;

this.startDebugServer().then(dbgServer => {
Expand All @@ -302,6 +292,7 @@ export class PythonDebugger extends LoggingDebugSession {
this.attachArgs = args;
this.debugClient = CreateAttachDebugClient(args, this);
this.entryResponse = response;
// tslint:disable-next-line:no-this-assignment
const that = this;

this.canStartDebugger().then(() => {
Expand Down Expand Up @@ -375,7 +366,7 @@ export class PythonDebugger extends LoggingDebugSession {
}

// VSC needs `id` to uniquely identify each breakpoint (part of the protocol spec).
const breakpoints: { verified: boolean, line: number, id: number }[] = [];
const breakpoints: { verified: boolean; line: number; id: number }[] = [];
const linesToAdd = args.breakpoints!.map(b => b.line);
const registeredBks = this.registeredBreakpointsByFileName.get(args.source.path!)!;
const linesToRemove = registeredBks.map(b => b.LineNo).filter(oldLine => linesToAdd.indexOf(oldLine) === -1);
Expand Down
13 changes: 12 additions & 1 deletion src/client/debugger/configProviders/baseProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import * as path from 'path';
import { CancellationToken, DebugConfiguration, DebugConfigurationProvider, ProviderResult, Uri, WorkspaceFolder } from 'vscode';
import { IDocumentManager, IWorkspaceService } from '../../common/application/types';
import { PythonLanguage } from '../../common/constants';
import { IFileSystem, IPlatformService } from '../../common/platform/types';
import { IConfigurationService } from '../../common/types';
import { IServiceContainer } from '../../ioc/types';
import { DebuggerType, LaunchRequestArguments } from '../Common/Contracts';

// tslint:disable:no-invalid-template-strings

export type PythonDebugConfiguration = DebugConfiguration & LaunchRequestArguments;
export type PTVSDDebugConfiguration = PythonDebugConfiguration & { redirectOutput: boolean, fixFilePathCase: boolean };
export type PTVSDDebugConfiguration = PythonDebugConfiguration & { redirectOutput: boolean; fixFilePathCase: boolean };

@injectable()
export abstract class BaseConfigurationProvider implements DebugConfigurationProvider {
Expand Down Expand Up @@ -64,6 +65,16 @@ export abstract class BaseConfigurationProvider implements DebugConfigurationPro
if (debugConfiguration.debugOptions.indexOf('RedirectOutput') === -1) {
debugConfiguration.debugOptions.push('RedirectOutput');
}
if (debugConfiguration.debugOptions.indexOf('Pyramid') >= 0) {
const platformService = this.serviceContainer.get<IPlatformService>(IPlatformService);
const fs = this.serviceContainer.get<IFileSystem>(IFileSystem);
const pserve = platformService.isWindows ? 'pserve.exe' : 'pserve';
if (fs.fileExistsSync(debugConfiguration.pythonPath)) {
debugConfiguration.program = path.join(path.dirname(debugConfiguration.pythonPath), pserve);
} else {
debugConfiguration.program = pserve;
}
}
}
private getWorkspaceFolder(folder: WorkspaceFolder | undefined, config: PythonDebugConfiguration): Uri | undefined {
if (folder) {
Expand Down
3 changes: 3 additions & 0 deletions src/test/common/platform/filesystem.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ suite('FileSystem', () => {
test('Case sensitivity is not ignored when comparing file names on linux', async () => {
caseSensitivityFileCheck(false, false, true);
});
test('Check existence of files synchronously', async () => {
expect(fileSystem.fileExistsSync(__filename)).to.be.equal(true, 'file not found');
});

test('Test appending to file', async () => {
const dataToAppend = `Some Data\n${new Date().toString()}\nAnd another line`;
Expand Down
Loading