Skip to content

Commit 3493cfe

Browse files
committed
src/goDebug: respect user cwd debug configuration in noDebug
If the launch configuration contain the current working directory, run the program in that directory. Build the program in the directory containing the program to be built and then run the program in the given directory. Fixes #918 Change-Id: I2d20d00a68cb1999245c41c3c5b2cdf0e746a4ba Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/270437 Trust: Suzy Mueller <[email protected]> Run-TryBot: Suzy Mueller <[email protected]> TryBot-Result: kokoro <[email protected]> Reviewed-by: Hyang-Ah Hana Kim <[email protected]>
1 parent ec9a5f8 commit 3493cfe

File tree

5 files changed

+245
-11
lines changed

5 files changed

+245
-11
lines changed

src/debugAdapter/goDebug.ts

+55-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See LICENSE in the project root for license information.
44
*--------------------------------------------------------*/
55

6-
import { ChildProcess, execFile, spawn } from 'child_process';
6+
import { ChildProcess, execFile, spawn, spawnSync } from 'child_process';
77
import { EventEmitter } from 'events';
88
import * as fs from 'fs';
99
import { existsSync, lstatSync } from 'fs';
@@ -481,25 +481,68 @@ export class Delve {
481481
if (!!launchArgs.noDebug) {
482482
if (mode === 'debug') {
483483
this.noDebug = true;
484-
const runArgs = ['run'];
485-
const runOptions: { [key: string]: any } = { cwd: dirname, env };
484+
const build = ['build'];
485+
486+
const output = path.join(os.tmpdir(), 'out');
487+
build.push(`-o=${output}`);
488+
489+
const buildOptions: { [key: string]: any } = { cwd: dirname, env };
486490
if (launchArgs.buildFlags) {
487-
runArgs.push(launchArgs.buildFlags);
491+
build.push(launchArgs.buildFlags);
488492
}
493+
489494
if (isProgramDirectory) {
490-
runArgs.push('.');
495+
build.push('.');
491496
} else {
492-
runArgs.push(program);
493-
}
494-
if (launchArgs.args) {
495-
runArgs.push(...launchArgs.args);
497+
build.push(program);
496498
}
497499

498500
const goExe = getBinPathWithPreferredGopathGoroot('go', []);
499501
log(`Current working directory: ${dirname}`);
500-
log(`Running: ${goExe} ${runArgs.join(' ')}`);
502+
log(`Building: ${goExe} ${build.join(' ')}`);
503+
504+
// Use spawnSync to ensure that the binary exists before running it.
505+
const buffer = spawnSync(goExe, build, buildOptions);
506+
if (buffer.stderr && buffer.stderr.length > 0) {
507+
const str = buffer.stderr.toString();
508+
if (this.onstderr) {
509+
this.onstderr(str);
510+
}
511+
}
512+
if (buffer.stdout && buffer.stdout.length > 0) {
513+
const str = buffer.stdout.toString();
514+
if (this.onstdout) {
515+
this.onstdout(str);
516+
}
517+
}
518+
if (buffer.status) {
519+
logError(`Build process exiting with code: ${buffer.status} signal: ${buffer.signal}`);
520+
if (this.onclose) {
521+
this.onclose(buffer.status);
522+
}
523+
} else {
524+
log(`Build process exiting normally ${buffer.signal}`);
525+
}
526+
if (buffer.error) {
527+
reject(buffer.error);
528+
}
501529

502-
this.debugProcess = spawn(goExe, runArgs, runOptions);
530+
// Run the built binary
531+
let wd = dirname;
532+
if (!!launchArgs.cwd) {
533+
wd = launchArgs.cwd;
534+
}
535+
const runOptions: { [key: string]: any } = { cwd: wd, env };
536+
537+
const run = [];
538+
if (launchArgs.args) {
539+
run.push(...launchArgs.args);
540+
}
541+
542+
log(`Current working directory: ${wd}`);
543+
log(`Running: ${output} ${run.join(' ')}`);
544+
545+
this.debugProcess = spawn(output, run, runOptions);
503546
this.debugProcess.stderr.on('data', (chunk) => {
504547
const str = chunk.toString();
505548
if (this.onstderr) {
@@ -525,6 +568,7 @@ export class Delve {
525568
this.debugProcess.on('error', (err) => {
526569
reject(err);
527570
});
571+
528572
resolve();
529573
return;
530574
}

test/integration/goDebug.test.ts

+176
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as assert from 'assert';
22
import { ChildProcess, spawn } from 'child_process';
3+
import { debug } from 'console';
34
import * as fs from 'fs';
45
import getPort = require('get-port');
56
import * as http from 'http';
@@ -568,6 +569,181 @@ suite('Go Debug Adapter', function () {
568569
});
569570
});
570571

572+
suite('set current working directory', () => {
573+
test('should debug program with cwd set', async () => {
574+
const WD = path.join(DATA_ROOT, 'cwdTest');
575+
const PROGRAM = path.join(WD, 'cwdTest');
576+
const FILE = path.join(PROGRAM, 'main.go');
577+
const BREAKPOINT_LINE = 11;
578+
579+
const config = {
580+
name: 'Launch',
581+
type: 'go',
582+
request: 'launch',
583+
mode: 'auto',
584+
program: PROGRAM,
585+
cwd: WD,
586+
};
587+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
588+
589+
await dc.hitBreakpoint(debugConfig, getBreakpointLocation(FILE, BREAKPOINT_LINE));
590+
591+
await assertVariableValue('strdat', '"Hello, World!"');
592+
});
593+
594+
test('should debug program without cwd set', async () => {
595+
const WD = path.join(DATA_ROOT, 'cwdTest');
596+
const PROGRAM = path.join(WD, 'cwdTest');
597+
const FILE = path.join(PROGRAM, 'main.go');
598+
const BREAKPOINT_LINE = 11;
599+
600+
const config = {
601+
name: 'Launch',
602+
type: 'go',
603+
request: 'launch',
604+
mode: 'auto',
605+
program: PROGRAM,
606+
};
607+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
608+
609+
await dc.hitBreakpoint(debugConfig, getBreakpointLocation(FILE, BREAKPOINT_LINE));
610+
611+
await assertVariableValue('strdat', '"Goodbye, World."');
612+
});
613+
614+
test('should debug file program with cwd set', async () => {
615+
const WD = path.join(DATA_ROOT, 'cwdTest');
616+
const PROGRAM = path.join(WD, 'cwdTest', 'main.go');
617+
const FILE = PROGRAM;
618+
const BREAKPOINT_LINE = 11;
619+
620+
const config = {
621+
name: 'Launch',
622+
type: 'go',
623+
request: 'launch',
624+
mode: 'auto',
625+
program: PROGRAM,
626+
cwd: WD,
627+
};
628+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
629+
630+
await dc.hitBreakpoint(debugConfig, getBreakpointLocation(FILE, BREAKPOINT_LINE));
631+
632+
await assertVariableValue('strdat', '"Hello, World!"');
633+
});
634+
635+
test('should debug file program without cwd set', async () => {
636+
const WD = path.join(DATA_ROOT, 'cwdTest');
637+
const PROGRAM = path.join(WD, 'cwdTest', 'main.go');
638+
const FILE = PROGRAM;
639+
const BREAKPOINT_LINE = 11;
640+
641+
const config = {
642+
name: 'Launch',
643+
type: 'go',
644+
request: 'launch',
645+
mode: 'auto',
646+
program: PROGRAM,
647+
};
648+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
649+
650+
await dc.hitBreakpoint(debugConfig, getBreakpointLocation(FILE, BREAKPOINT_LINE));
651+
652+
await assertVariableValue('strdat', '"Goodbye, World."');
653+
});
654+
655+
test('should run program with cwd set (noDebug)', () => {
656+
const WD = path.join(DATA_ROOT, 'cwdTest');
657+
const PROGRAM = path.join(WD, 'cwdTest');
658+
659+
const config = {
660+
name: 'Launch',
661+
type: 'go',
662+
request: 'launch',
663+
mode: 'auto',
664+
program: PROGRAM,
665+
cwd: WD,
666+
noDebug: true
667+
};
668+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
669+
670+
return Promise.all([
671+
dc.launch(debugConfig),
672+
dc.waitForEvent('output').then((event) => {
673+
assert.strictEqual(event.body.output, 'Hello, World!\n');
674+
})
675+
]);
676+
});
677+
678+
test('should run program without cwd set (noDebug)', () => {
679+
const WD = path.join(DATA_ROOT, 'cwdTest');
680+
const PROGRAM = path.join(WD, 'cwdTest');
681+
682+
const config = {
683+
name: 'Launch',
684+
type: 'go',
685+
request: 'launch',
686+
mode: 'auto',
687+
program: PROGRAM,
688+
noDebug: true
689+
};
690+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
691+
692+
return Promise.all([
693+
dc.launch(debugConfig),
694+
dc.waitForEvent('output').then((event) => {
695+
assert.strictEqual(event.body.output, 'Goodbye, World.\n');
696+
})
697+
]);
698+
});
699+
700+
test('should run file program with cwd set (noDebug)', () => {
701+
const WD = path.join(DATA_ROOT, 'cwdTest');
702+
const PROGRAM = path.join(WD, 'cwdTest', 'main.go');
703+
704+
const config = {
705+
name: 'Launch',
706+
type: 'go',
707+
request: 'launch',
708+
mode: 'auto',
709+
program: PROGRAM,
710+
cwd: WD,
711+
noDebug: true
712+
};
713+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
714+
715+
return Promise.all([
716+
dc.launch(debugConfig),
717+
dc.waitForEvent('output').then((event) => {
718+
assert.strictEqual(event.body.output, 'Hello, World!\n');
719+
})
720+
]);
721+
});
722+
723+
test('should run file program without cwd set (noDebug)', () => {
724+
const WD = path.join(DATA_ROOT, 'cwdTest');
725+
const PROGRAM = path.join(WD, 'cwdTest', 'main.go');
726+
727+
const config = {
728+
name: 'Launch',
729+
type: 'go',
730+
request: 'launch',
731+
mode: 'auto',
732+
program: PROGRAM,
733+
noDebug: true
734+
};
735+
const debugConfig = debugConfigProvider.resolveDebugConfiguration(undefined, config);
736+
737+
return Promise.all([
738+
dc.launch(debugConfig),
739+
dc.waitForEvent('output').then((event) => {
740+
assert.strictEqual(event.body.output, 'Goodbye, World.\n');
741+
})
742+
]);
743+
});
744+
745+
});
746+
571747
suite('remote attach', () => {
572748
let childProcess: ChildProcess;
573749
let server: number;
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Goodbye, World.

test/testdata/cwdTest/cwdTest/main.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
)
7+
8+
func main() {
9+
dat, _ := ioutil.ReadFile("hello.txt")
10+
strdat := string(dat)
11+
fmt.Println(strdat)
12+
}

test/testdata/cwdTest/hello.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello, World!

0 commit comments

Comments
 (0)