-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redirect if internal console #3108
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -273,11 +273,9 @@ const ( | |
maxStringLenInCallRetVars = 1 << 10 // 1024 | ||
) | ||
|
||
var ( | ||
// Max number of goroutines that we will return. | ||
// This is a var for testing | ||
maxGoroutines = 1 << 10 | ||
) | ||
// Max number of goroutines that we will return. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid unrelated reformats, they pollute blames and make merge conflicts unnecessarily harder. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My editor auto-formats using |
||
// This is a var for testing | ||
var maxGoroutines = 1 << 10 | ||
|
||
// NewServer creates a new DAP Server. It takes an opened Listener | ||
// via config and assumes its ownership. config.DisconnectChan has to be set; | ||
|
@@ -805,7 +803,24 @@ func (s *Session) logToConsole(msg string) { | |
Body: dap.OutputEventBody{ | ||
Output: msg + "\n", | ||
Category: "console", | ||
}}) | ||
}, | ||
}) | ||
} | ||
|
||
type debugConsoleLogger struct { | ||
session *Session | ||
category string | ||
} | ||
|
||
func (l *debugConsoleLogger) Write(p []byte) (int, error) { | ||
l.session.send(&dap.OutputEvent{ | ||
Event: *newEvent("output"), | ||
Body: dap.OutputEventBody{ | ||
Output: string(p), | ||
Category: l.category, | ||
}, | ||
}) | ||
return len(p), nil | ||
} | ||
|
||
func (s *Session) onInitializeRequest(request *dap.InitializeRequest) { | ||
|
@@ -881,7 +896,7 @@ func (s *Session) onLaunchRequest(request *dap.LaunchRequest) { | |
return | ||
} | ||
|
||
var args = defaultLaunchConfig // narrow copy for initializing non-zero default values | ||
args := defaultLaunchConfig // narrow copy for initializing non-zero default values | ||
if err := unmarshalLaunchAttachArgs(request.Arguments, &args); err != nil { | ||
s.sendShowUserErrorResponse(request.Request, | ||
FailedToLaunch, "Failed to launch", fmt.Sprintf("invalid debug configuration - %v", err)) | ||
|
@@ -989,7 +1004,8 @@ func (s *Session) onLaunchRequest(request *dap.LaunchRequest) { | |
Body: dap.OutputEventBody{ | ||
Output: fmt.Sprintf("Build Error: %s\n%s (%s)\n", cmd, strings.TrimSpace(string(out)), err.Error()), | ||
Category: "stderr", | ||
}}) | ||
}, | ||
}) | ||
// Users are used to checking the Debug Console for build errors. | ||
// No need to bother them with a visible pop-up. | ||
s.sendErrorResponse(request.Request, FailedToLaunch, "Failed to launch", | ||
|
@@ -1028,6 +1044,12 @@ func (s *Session) onLaunchRequest(request *dap.LaunchRequest) { | |
if args.NoDebug { | ||
s.mu.Lock() | ||
cmd, err := s.newNoDebugProcess(debugbinary, args.Args, s.config.Debugger.WorkingDir) | ||
if args.Console == "internalConsole" { | ||
cmd.Stdout, cmd.Stderr = &debugConsoleLogger{session: s, category: "stdout"}, &debugConsoleLogger{session: s, category: "stderr"} | ||
} | ||
if err == nil { | ||
err = cmd.Start() | ||
} | ||
s.mu.Unlock() | ||
if err != nil { | ||
s.sendShowUserErrorResponse(request.Request, FailedToLaunch, "Failed to launch", err.Error()) | ||
|
@@ -1049,6 +1071,32 @@ func (s *Session) onLaunchRequest(request *dap.LaunchRequest) { | |
return | ||
} | ||
|
||
func() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Followed a similar pattern I've seen later on of wrapping some logic in an inline function to ease breaking, not anything special - I can export it to a different method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you refer to this file, that pattern is to execute a defer, not to group anything. |
||
if args.Console == "internalConsole" && runtime.GOOS == "linux" && (args.Backend == "default" || args.Backend == "native") { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's weird that using internalConsole on an unsupported configuration fails silently. It's also weird that all values of console that aren't internalConsole are accepted as valid. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current behavior is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suppose someone misspells internlaConsole, how do they notice? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Usually, such syntax can be checked in VSCode itself - it can present an error such as: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not everyone uses vscode with dap. I thought that was the whole point of this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, true. I am not familiar with how every DAP client handles this, but adding an allowed list of declared DAP consoles (I think it is standardized) should be easy enough. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it should just be the consoles that we support. |
||
redirects, err := generateStdioTempPipes() | ||
if err != nil { | ||
return | ||
} | ||
s.config.Debugger.Redirects[1] = redirects[0] | ||
s.config.Debugger.Redirects[2] = redirects[1] | ||
|
||
stdoutWriter := &debugConsoleLogger{session: s, category: "stdout"} | ||
stderrWriter := &debugConsoleLogger{session: s, category: "stderr"} | ||
f := func(pipePath string, w io.Writer) { | ||
// Blocking until read side of the pipe succeeds, and then delete file | ||
pipe, err := os.Open(pipePath) | ||
os.Remove(pipePath) | ||
if err != nil { | ||
return | ||
} | ||
defer pipe.Close() | ||
io.Copy(w, pipe) | ||
} | ||
go f(redirects[0], stdoutWriter) | ||
go f(redirects[1], stderrWriter) | ||
} | ||
}() | ||
|
||
func() { | ||
s.mu.Lock() | ||
defer s.mu.Unlock() // Make sure to unlock in case of panic that will become internal error | ||
|
@@ -1088,9 +1136,6 @@ func (s *Session) newNoDebugProcess(program string, targetArgs []string, wd stri | |
} | ||
cmd := exec.Command(program, targetArgs...) | ||
cmd.Stdout, cmd.Stderr, cmd.Stdin, cmd.Dir = os.Stdout, os.Stderr, os.Stdin, wd | ||
if err := cmd.Start(); err != nil { | ||
return nil, err | ||
} | ||
s.noDebugProcess = &process{Cmd: cmd, exited: make(chan struct{})} | ||
return cmd, nil | ||
} | ||
|
@@ -1571,7 +1616,8 @@ func (s *Session) onConfigurationDoneRequest(request *dap.ConfigurationDoneReque | |
func (s *Session) onContinueRequest(request *dap.ContinueRequest, allowNextStateChange chan struct{}) { | ||
s.send(&dap.ContinueResponse{ | ||
Response: *newResponse(request.Request), | ||
Body: dap.ContinueResponseBody{AllThreadsContinued: true}}) | ||
Body: dap.ContinueResponseBody{AllThreadsContinued: true}, | ||
}) | ||
s.runUntilStopAndNotify(api.Continue, allowNextStateChange) | ||
} | ||
|
||
|
@@ -1635,7 +1681,8 @@ func (s *Session) onThreadsRequest(request *dap.ThreadsRequest) { | |
Body: dap.OutputEventBody{ | ||
Output: fmt.Sprintf("Unable to retrieve goroutines: %s\n", err.Error()), | ||
Category: "stderr", | ||
}}) | ||
}, | ||
}) | ||
} | ||
threads = []dap.Thread{{Id: 1, Name: "Dummy"}} | ||
} else if len(gs) == 0 { | ||
|
@@ -2463,7 +2510,7 @@ func (s *Session) convertVariableWithOpts(v *proc.Variable, qualifiedNameOrExpr | |
|
||
// Some of the types might be fully or partially not loaded based on LoadConfig. | ||
// Those that are fully missing (e.g. due to hitting MaxVariableRecurse), can be reloaded in place. | ||
var reloadVariable = func(v *proc.Variable, qualifiedNameOrExpr string) (value string) { | ||
reloadVariable := func(v *proc.Variable, qualifiedNameOrExpr string) (value string) { | ||
// We might be loading variables from the frame that's not topmost, so use | ||
// frame-independent address-based expression, not fully-qualified name as per | ||
// https://github.com/go-delve/delve/blob/master/Documentation/api/ClientHowto.md#looking-into-variables. | ||
|
@@ -3393,6 +3440,7 @@ func newEvent(event string) *dap.Event { | |
|
||
const BetterBadAccessError = `invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation] | ||
Unable to propagate EXC_BAD_ACCESS signal to target process and panic (see https://github.com/go-delve/delve/issues/852)` | ||
|
||
const BetterNextWhileNextingError = `Unable to step while the previous step is interrupted by a breakpoint. | ||
Use 'Continue' to resume the original step command.` | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
//go:build !linux | ||
// +build !linux | ||
|
||
package dap | ||
|
||
import ( | ||
"errors" | ||
) | ||
|
||
func generateStdioTempPipes() (res [2]string, err error) { | ||
err = errors.New("Unimplemented") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Merging this with just a linux implementation would be weird. This is enough of a prominent feature that having it implemented for one operating system implies that we have to implement it for at least the more important ones. I think it needs to support Windows and macOS. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implementing it to all platforms should be relatively easier if we can change the |
||
return res, err | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//go:build linux | ||
// +build linux | ||
|
||
package dap | ||
|
||
import ( | ||
"crypto/rand" | ||
"encoding/hex" | ||
"os" | ||
"path/filepath" | ||
"syscall" | ||
) | ||
|
||
func generateStdioTempPipes() (res [2]string, err error) { | ||
r := make([]byte, 4) | ||
if _, err := rand.Read(r); err != nil { | ||
return res, err | ||
} | ||
prefix := filepath.Join(os.TempDir(), hex.EncodeToString(r)) | ||
stdoutPath := prefix + "stdout" | ||
stderrPath := prefix + "stderr" | ||
if err := syscall.Mkfifo(stdoutPath, 0o600); err != nil { | ||
return res, err | ||
} | ||
if err := syscall.Mkfifo(stderrPath, 0o600); err != nil { | ||
os.Remove(stdoutPath) | ||
return res, err | ||
} | ||
|
||
res[0] = stdoutPath | ||
res[1] = stderrPath | ||
return res, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a backwards incompatible change because you are not passsing O_TRUNC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will add it - I still need to check whether
O_TRUNC
has any bad effect when opening a fifo.