diff --git a/package.json b/package.json index ead9499..fe22542 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "rech-cobol-debugger", "displayName": "Rech COBOL Debugger", "description": "Debug COBOL files with Visual Studio Code", - "version": "1.0.41", + "version": "1.0.42", "publisher": "rechinformatica", "engines": { "vscode": "^1.47.0" @@ -152,6 +152,12 @@ "type": "string", "description": "Path to the file where trace will be stored. When specified, every interaction with the external command-line debugger will be logged on this file.", "default": "" + }, + "rech.cobol.debug.externalPathResolver": { + "type": "string", + "title": "Command Line", + "description": "Command line to resolve path for remote debugger. This command will be called whenever a file path is not recognized passing the path as a parameter, useful for debugging on a different operating system than the current.", + "default": "" } } }, diff --git a/src/CobolDebug.ts b/src/CobolDebug.ts index 3c26e93..6f9bfda 100644 --- a/src/CobolDebug.ts +++ b/src/CobolDebug.ts @@ -123,7 +123,8 @@ export class CobolDebugSession extends DebugSession { const commandLine = (args).commandLine; const configFilePath = this.locateConfiguredDebugFile(); const traceFilePath = this.locateTraceFile(); - this.debugRuntime = new ExternalDebugAdapter(commandLine, this.appendOutputToDebugConsole, configFilePath, traceFilePath); + const externalPathResolver = this.externalPathResolver(); + this.debugRuntime = new ExternalDebugAdapter(commandLine, this.appendOutputToDebugConsole, configFilePath, traceFilePath, externalPathResolver); // Gets information about the first line of source code this.debugRuntime.start().then((position) => { // Finally, tells VSCode API/UI to position on first line of source code @@ -148,6 +149,12 @@ export class CobolDebugSession extends DebugSession { return traceFile; } + private externalPathResolver(): string { + const configuration = new Configuration("rech.cobol.debug") + const externalPathResolver = configuration.get("externalPathResolver"); + return externalPathResolver; + } + private onProblemStartingDebugger(response: DebugProtocol.LaunchResponse): void { window.showWarningMessage("Could not start external COBOL debugger."); this.fireTerminateDebugEvent(response); diff --git a/src/debugProcess/ExternalDebugAdapter.ts b/src/debugProcess/ExternalDebugAdapter.ts index 64f0638..9db3d97 100644 --- a/src/debugProcess/ExternalDebugAdapter.ts +++ b/src/debugProcess/ExternalDebugAdapter.ts @@ -40,6 +40,7 @@ export class ExternalDebugAdapter implements DebugInterface { outputRedirector: (output: string) => void, configFilePath: string, traceFilePath: string, + externalPathResolver: string, processProvider?: ProcessProvider) { @@ -53,7 +54,7 @@ export class ExternalDebugAdapter implements DebugInterface { this.retriesRegexes = retriesText ? this.createRegExpArray(retriesText) : undefined; - this.fallbackFinder = new FallbackDirectoriesFinder(this); + this.fallbackFinder = new FallbackDirectoriesFinder(this, externalPathResolver); // Spawns the external debug process itself const commandTerminator = this.configs.commandTerminator; diff --git a/src/debugProcess/FallbackDirectoriesFinder.ts b/src/debugProcess/FallbackDirectoriesFinder.ts index 8a547ac..5a7abaa 100644 --- a/src/debugProcess/FallbackDirectoriesFinder.ts +++ b/src/debugProcess/FallbackDirectoriesFinder.ts @@ -1,6 +1,7 @@ import * as path from "path"; import * as fs from "fs"; import { ExternalDebugAdapter } from "./ExternalDebugAdapter"; +import { execSync } from "child_process"; /** * Class to look for files on fallback directories @@ -9,8 +10,11 @@ export class FallbackDirectoriesFinder { private cachedFiles: Map = new Map(); private cachedAvailableSourceDirectories: string[] | undefined; + private externalPathResolver: string | undefined; - constructor(private externalDebugAdaptar: ExternalDebugAdapter) { } + constructor(private externalDebugAdaptar: ExternalDebugAdapter, externalPathResolver?: string) { + this.externalPathResolver = externalPathResolver; + } public lookForSourceOnFallbackDirectories(fileName: string): Promise { return new Promise((resolve, reject) => { @@ -37,7 +41,13 @@ export class FallbackDirectoriesFinder { } private lookForFileWithoutCache(currentDir: string, fileName: string): string | undefined { - const fileOnCurrentDirectory = this.addSeparatorIfNeeded(currentDir.trim()) + fileName; + let resolvedDir = currentDir; + try { + if (this.externalPathResolver && this.externalPathResolver.length != 0) { + resolvedDir = execSync(`${this.externalPathResolver} ${currentDir}`).toString(); + } + } catch (e) {} + const fileOnCurrentDirectory = this.addSeparatorIfNeeded(resolvedDir.trim()) + fileName; if (fs.existsSync(fileOnCurrentDirectory)) { this.cachedFiles.set(fileName, fileOnCurrentDirectory); return fileOnCurrentDirectory; diff --git a/src/debugProcess/RequestAvailableSourceDirectoriesCommand.ts b/src/debugProcess/RequestAvailableSourceDirectoriesCommand.ts index 210ac62..1e13f2d 100644 --- a/src/debugProcess/RequestAvailableSourceDirectoriesCommand.ts +++ b/src/debugProcess/RequestAvailableSourceDirectoriesCommand.ts @@ -26,7 +26,13 @@ export class RequestAvailableSourceDirectoriesCommand implements DebugCommand { it('Hits breakpoint on continue', async () => { const expected: DebugPosition = { file: 'F:/SIGER/wc/DES/lucas-camargo/src/isCOBOL/debug/PDV201.CBL', line: 75151, output: 'dummy' }; - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new HitBreakpointProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new HitBreakpointProvider()); const result = await adapter.continue(); expect(expected.file).to.equal(result.file); expect(expected.line).to.equal(result.line); @@ -16,7 +16,7 @@ describe('External debug adapter', () => { it('Hits breakpoint on step in', async () => { const expected: DebugPosition = { file: 'F:/SIGER/wc/DES/lucas-camargo/src/isCOBOL/debug/PDV201.CBL', line: 75151, output: 'dummy' }; - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new HitBreakpointProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new HitBreakpointProvider()); const result = await adapter.stepIn(); expect(expected.file).to.equal(result.file); expect(expected.line).to.equal(result.line); @@ -24,7 +24,7 @@ describe('External debug adapter', () => { it('Hits breakpoint on step out', async () => { const expected: DebugPosition = { file: 'F:/SIGER/wc/DES/lucas-camargo/src/isCOBOL/debug/PDV201.CBL', line: 75151, output: 'dummy' }; - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new HitBreakpointProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new HitBreakpointProvider()); const result = await adapter.stepOut(); expect(expected.file).to.equal(result.file); expect(expected.line).to.equal(result.line); @@ -32,7 +32,7 @@ describe('External debug adapter', () => { it('Hits breakpoint on step out program', async () => { const expected: DebugPosition = { file: 'F:/SIGER/wc/DES/lucas-camargo/src/isCOBOL/debug/PDV201.CBL', line: 75151, output: 'dummy' }; - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new HitBreakpointProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new HitBreakpointProvider()); const result = await adapter.stepOutProgram(); expect(expected.file).to.equal(result.file); expect(expected.line).to.equal(result.line); @@ -40,7 +40,7 @@ describe('External debug adapter', () => { it('Hits breakpoint on run to next program', async () => { const expected: DebugPosition = { file: 'F:/SIGER/wc/DES/lucas-camargo/src/isCOBOL/debug/PDV201.CBL', line: 75151, output: 'dummy' }; - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new HitBreakpointProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new HitBreakpointProvider()); const result = await adapter.runToNextProgram(); expect(expected.file).to.equal(result.file); expect(expected.line).to.equal(result.line); @@ -48,7 +48,7 @@ describe('External debug adapter', () => { it('Hits breakpoint on next', async () => { const expected: DebugPosition = { file: 'F:/SIGER/wc/DES/lucas-camargo/src/isCOBOL/debug/PDV201.CBL', line: 75151, output: 'dummy' }; - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new HitBreakpointProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new HitBreakpointProvider()); const result = await adapter.next(); expect(expected.file).to.equal(result.file); expect(expected.line).to.equal(result.line); @@ -56,85 +56,85 @@ describe('External debug adapter', () => { it('Adds breakpoint', async () => { const expected = 'F:/SIGER/20.10a/src/is-COBOL/debug/SRIM00.CBL'; - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new AddBreakpointProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new AddBreakpointProvider()); const result = await adapter.addBreakpoint({ line: 55682, source: 'SRIM00.CBL' }) expect(expected).to.equal(result); }); it('Removes breakpoint', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new RemoveBreakpointProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new RemoveBreakpointProvider()); const result = await adapter.removeBreakpoint({ line: 55682, source: 'F:/SIGER/20.10a/src/isCOBOL/debug/SRIM00.CBL' }) expect(true).to.equal(result); }); it('Unmonitors with success', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new UnmonitorSuccessProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new UnmonitorSuccessProvider()); const result = await adapter.removeMonitor('w-dummy-var'); expect(true).to.equal(result); }); it('Unmonitors with failure', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new UnmonitorFailureProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new UnmonitorFailureProvider()); const result = await adapter.removeMonitor('w-dummy-var'); expect(false).to.equal(result); }); it('Unmonitors all variables with success', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new UnmonitorAllSuccessProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new UnmonitorAllSuccessProvider()); const result = await adapter.removeAllMonitors(); expect(true).to.equal(result); }); it('Unmonitors all variables with failure', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new UnmonitorAllFailureProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new UnmonitorAllFailureProvider()); const result = await adapter.removeAllMonitors(); expect(false).to.equal(result); }); it('Monitors variable', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new MonitorProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new MonitorProvider()); const result = await adapter.addMonitor({ variable: 'w-dummy-var', condition: 'always' }); expect(true).to.equal(result); }); it('Changes variable value', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new ChangeValueProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new ChangeValueProvider()); const result = await adapter.changeVariableValue('w-dummy-var', 'L'); expect(true).to.equal(result); }); it('Changes variable value in hexadecimal', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new ChangeValueProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new ChangeValueProvider()); const result = await adapter.changeVariableValue('-x w-dummy-var', '20'); expect(true).to.equal(result); }); it('Changes variable value with subindex', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new ChangeValueProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new ChangeValueProvider()); const result = await adapter.changeVariableValue('wapi-r07-nomdco(wapi-r07-tadcoc:1)', 'L'); expect(true).to.equal(result); }); it('Changes variable value with subindex and hexadecimal', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new ChangeValueProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new ChangeValueProvider()); const result = await adapter.changeVariableValue('-x wapi-r07-nomdco(wapi-r07-tadcoc:1)', 'L'); expect(true).to.equal(result); }); it('Requests variable value', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new RequestValueProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new RequestValueProvider()); const result = await adapter.requestVariableValue('w-dummy-var'); expect('true [S] ').to.equal(result); }); it('Requests variable value in hexadecimal', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new RequestValueInHexProvider()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new RequestValueInHexProvider()); const result = await adapter.requestVariableValue('-x w-dummy-var'); expect('63617373656C202020202020202020').to.equal(result); }); it('Requests a variable value thas is not allocated', async () => { - const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", new RequestValueNotAllocated()); + const adapter = new ExternalDebugAdapter("dummyCommandLine", () => { }, "", "", "", new RequestValueNotAllocated()); const result = await adapter.requestVariableValue('wninf-pro'); expect(undefined).to.equal(result); }); diff --git a/src/test/debugProcess/RequestAvailableSourceDirectoriesCommand.test.ts b/src/test/debugProcess/RequestAvailableSourceDirectoriesCommand.test.ts index 2d3b011..d24ae5b 100644 --- a/src/test/debugProcess/RequestAvailableSourceDirectoriesCommand.test.ts +++ b/src/test/debugProcess/RequestAvailableSourceDirectoriesCommand.test.ts @@ -10,7 +10,7 @@ const COMMAND: ICommand = { describe('Request available source directories command', () => { - it('Checks a single available directory', () => { + it('Checks a single available windows directory', () => { const output = ' \n' + ' + java.class.path = F:\\SIGER\\wc\\DES\\cassel\\bin\\isCOBOL\\debug\n' + @@ -21,7 +21,7 @@ describe('Request available source directories command', () => { expect(expected[0]).to.equal(result![0]); }); - it('Checks two available directories', () => { + it('Checks two available windows directories', () => { const output = ' \n' + ' + java.class.path = F:\\SIGER\\wc\\DES\\cassel\\bin\\isCOBOL\\debug;F:\\SIGER\\wc\\DES\\cassel\\src\\isCOBOL\\debug\n' + @@ -33,5 +33,28 @@ describe('Request available source directories command', () => { expect(expected[1]).to.equal(result![1]); }); + it('Checks a single available linux directory', () => { + const output = + ' \n' + + ' + java.class.path = /SIGER/wc/DES/cassel/bin/isCOBOL/debug\n' + + 'isdb>'; + const expected: string[] = ['/SIGER/wc/DES/cassel/bin/isCOBOL/debug']; + const result = new RequestAvailableSourceDirectoriesCommand(COMMAND).validateOutput(output); + expect(expected.length).to.equal(result!.length); + expect(expected[0]).to.equal(result![0]); + }); + + it('Checks two available linux directories', () => { + const output = + ' \n' + + ' + java.class.path = /SIGER/wc/DES/cassel/bin/isCOBOL/debug:/SIGER/wc/DES/cassel/src/isCOBOL/debug\n' + + 'isdb>'; + const expected: string[] = ['/SIGER/wc/DES/cassel/bin/isCOBOL/debug', '/SIGER/wc/DES/cassel/src/isCOBOL/debug']; + const result = new RequestAvailableSourceDirectoriesCommand(COMMAND).validateOutput(output); + expect(expected.length).to.equal(result!.length); + expect(expected[0]).to.equal(result![0]); + expect(expected[1]).to.equal(result![1]); + }); + }); diff --git a/src/test/repl/DebuggerReplManager.test.ts b/src/test/repl/DebuggerReplManager.test.ts index 90d4fd0..59676bb 100644 --- a/src/test/repl/DebuggerReplManager.test.ts +++ b/src/test/repl/DebuggerReplManager.test.ts @@ -119,7 +119,7 @@ function validateBreakpoint(expected: CobolBreakpoint, bp: CobolBreakpoint): voi class TestDebugAdapter extends ExternalDebugAdapter { constructor(processProvider: ProcessProvider) { - super("", () => { }, "", "", processProvider); + super("", () => { }, "", "", "", processProvider); } }