mirror of
https://github.com/go-delve/delve.git
synced 2025-10-29 17:56:45 +08:00
dlv: Misc refactors
This commit is contained in:
committed by
Derek Parker
parent
ff0ec8ce00
commit
37f124817d
@ -255,7 +255,7 @@ func traceCmd(cmd *cobra.Command, args []string) {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
for i := range funcs {
|
for i := range funcs {
|
||||||
_, err := client.CreateBreakpoint(&api.Breakpoint{FunctionName: funcs[i], Tracepoint: true, Line: -1, Stacktrace: traceStackDepth})
|
_, err = client.CreateBreakpoint(&api.Breakpoint{FunctionName: funcs[i], Tracepoint: true, Line: -1, Stacktrace: traceStackDepth})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@ -24,7 +24,7 @@ type Config struct {
|
|||||||
func LoadConfig() *Config {
|
func LoadConfig() *Config {
|
||||||
err := createConfigPath()
|
err := createConfigPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Could not create config directory: %v.")
|
fmt.Printf("Could not create config directory: %v.", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
fullConfigFile, err := GetConfigFilePath(configFile)
|
fullConfigFile, err := GetConfigFilePath(configFile)
|
||||||
|
|||||||
@ -25,8 +25,8 @@ type Breakpoint struct {
|
|||||||
|
|
||||||
// Breakpoint information
|
// Breakpoint information
|
||||||
Tracepoint bool // Tracepoint flag
|
Tracepoint bool // Tracepoint flag
|
||||||
Stacktrace int // Number of stack frames to retrieve
|
|
||||||
Goroutine bool // Retrieve goroutine information
|
Goroutine bool // Retrieve goroutine information
|
||||||
|
Stacktrace int // Number of stack frames to retrieve
|
||||||
Variables []string // Variables to evaluate
|
Variables []string // Variables to evaluate
|
||||||
HitCount map[int]uint64 // Number of times a breakpoint has been reached in a certain goroutine
|
HitCount map[int]uint64 // Number of times a breakpoint has been reached in a certain goroutine
|
||||||
TotalHitCount uint64 // Number of times a breakpoint has been reached
|
TotalHitCount uint64 // Number of times a breakpoint has been reached
|
||||||
|
|||||||
19
proc/eval.go
19
proc/eval.go
@ -9,10 +9,10 @@ import (
|
|||||||
"go/parser"
|
"go/parser"
|
||||||
"go/printer"
|
"go/printer"
|
||||||
"go/token"
|
"go/token"
|
||||||
"golang.org/x/debug/dwarf"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/derekparker/delve/dwarf/reader"
|
"github.com/derekparker/delve/dwarf/reader"
|
||||||
|
"golang.org/x/debug/dwarf"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EvalExpression returns the value of the given expression.
|
// EvalExpression returns the value of the given expression.
|
||||||
@ -430,26 +430,27 @@ func (scope *EvalScope) evalIdent(node *ast.Ident) (*Variable, error) {
|
|||||||
|
|
||||||
// try to interpret this as a local variable
|
// try to interpret this as a local variable
|
||||||
v, err := scope.extractVarInfo(node.Name)
|
v, err := scope.extractVarInfo(node.Name)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
origErr := err
|
origErr := err
|
||||||
// workaround: sometimes go inserts an entry for '&varname' instead of varname
|
// workaround: sometimes go inserts an entry for '&varname' instead of varname
|
||||||
v, err = scope.extractVarInfo("&" + node.Name)
|
v, err = scope.extractVarInfo("&" + node.Name)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
|
v = v.maybeDereference()
|
||||||
|
v.Name = node.Name
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
// if it's not a local variable then it could be a package variable w/o explicit package name
|
// if it's not a local variable then it could be a package variable w/o explicit package name
|
||||||
_, _, fn := scope.Thread.dbp.PCToLine(scope.PC)
|
_, _, fn := scope.Thread.dbp.PCToLine(scope.PC)
|
||||||
if fn != nil {
|
if fn != nil {
|
||||||
if v, err := scope.packageVarAddr(fn.PackageName() + "." + node.Name); err == nil {
|
if v, err = scope.packageVarAddr(fn.PackageName() + "." + node.Name); err == nil {
|
||||||
v.Name = node.Name
|
v.Name = node.Name
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, origErr
|
return nil, origErr
|
||||||
}
|
}
|
||||||
v = v.maybeDereference()
|
|
||||||
v.Name = node.Name
|
|
||||||
}
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluates expressions <subexpr>.<field name> where subexpr is not a package name
|
// Evaluates expressions <subexpr>.<field name> where subexpr is not a package name
|
||||||
func (scope *EvalScope) evalStructSelector(node *ast.SelectorExpr) (*Variable, error) {
|
func (scope *EvalScope) evalStructSelector(node *ast.SelectorExpr) (*Variable, error) {
|
||||||
|
|||||||
@ -49,11 +49,11 @@ type Process struct {
|
|||||||
goSymTable *gosym.Table
|
goSymTable *gosym.Table
|
||||||
frameEntries frame.FrameDescriptionEntries
|
frameEntries frame.FrameDescriptionEntries
|
||||||
lineInfo line.DebugLines
|
lineInfo line.DebugLines
|
||||||
firstStart bool
|
|
||||||
os *OSProcessDetails
|
os *OSProcessDetails
|
||||||
arch Arch
|
arch Arch
|
||||||
breakpointIDCounter int
|
breakpointIDCounter int
|
||||||
tempBreakpointIDCounter int
|
tempBreakpointIDCounter int
|
||||||
|
firstStart bool
|
||||||
halt bool
|
halt bool
|
||||||
exited bool
|
exited bool
|
||||||
ptraceChan chan func()
|
ptraceChan chan func()
|
||||||
|
|||||||
@ -84,9 +84,9 @@ func (n NullAddrError) Error() string {
|
|||||||
type StackIterator struct {
|
type StackIterator struct {
|
||||||
pc, sp uint64
|
pc, sp uint64
|
||||||
top bool
|
top bool
|
||||||
|
atend bool
|
||||||
frame Stackframe
|
frame Stackframe
|
||||||
dbp *Process
|
dbp *Process
|
||||||
atend bool
|
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -396,16 +396,16 @@ func (thread *Thread) onRuntimeBreakpoint() bool {
|
|||||||
return loc.Fn != nil && loc.Fn.Name == "runtime.breakpoint"
|
return loc.Fn != nil && loc.Fn.Name == "runtime.breakpoint"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if this thread is on the goroutine requested by the current 'next' command
|
// onNextGorutine returns true if this thread is on the goroutine requested by the current 'next' command
|
||||||
func (th *Thread) onNextGoroutine() (bool, error) {
|
func (thread *Thread) onNextGoroutine() (bool, error) {
|
||||||
var bp *Breakpoint
|
var bp *Breakpoint
|
||||||
for i := range th.dbp.Breakpoints {
|
for i := range thread.dbp.Breakpoints {
|
||||||
if th.dbp.Breakpoints[i].Temp {
|
if thread.dbp.Breakpoints[i].Temp {
|
||||||
bp = th.dbp.Breakpoints[i]
|
bp = thread.dbp.Breakpoints[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if bp == nil {
|
if bp == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
return bp.checkCondition(th)
|
return bp.checkCondition(thread)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,11 +8,12 @@ import (
|
|||||||
"go/constant"
|
"go/constant"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"golang.org/x/debug/dwarf"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/debug/dwarf"
|
||||||
|
|
||||||
"github.com/derekparker/delve/dwarf/op"
|
"github.com/derekparker/delve/dwarf/op"
|
||||||
"github.com/derekparker/delve/dwarf/reader"
|
"github.com/derekparker/delve/dwarf/reader"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,14 +14,14 @@ const (
|
|||||||
indentString = "\t"
|
indentString = "\t"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Returns a representation of v on a single line
|
// SinglelineString returns a representation of v on a single line.
|
||||||
func (v *Variable) SinglelineString() string {
|
func (v *Variable) SinglelineString() string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
v.writeTo(&buf, true, false, true, "")
|
v.writeTo(&buf, true, false, true, "")
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a representation of v on multiple lines
|
// MultilineString returns a representation of v on multiple lines.
|
||||||
func (v *Variable) MultilineString(indent string) string {
|
func (v *Variable) MultilineString(indent string) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(indent)
|
buf.WriteString(indent)
|
||||||
@ -28,7 +29,7 @@ func (v *Variable) MultilineString(indent string) string {
|
|||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Variable) writeTo(buf *bytes.Buffer, top, newlines, includeType bool, indent string) {
|
func (v *Variable) writeTo(buf io.Writer, top, newlines, includeType bool, indent string) {
|
||||||
if v.Unreadable != "" {
|
if v.Unreadable != "" {
|
||||||
fmt.Fprintf(buf, "(unreadable %s)", v.Unreadable)
|
fmt.Fprintf(buf, "(unreadable %s)", v.Unreadable)
|
||||||
return
|
return
|
||||||
@ -101,7 +102,7 @@ func (v *Variable) writeTo(buf *bytes.Buffer, top, newlines, includeType bool, i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Variable) writeStringTo(buf *bytes.Buffer) {
|
func (v *Variable) writeStringTo(buf io.Writer) {
|
||||||
s := v.Value
|
s := v.Value
|
||||||
if len(s) != int(v.Len) {
|
if len(s) != int(v.Len) {
|
||||||
s = fmt.Sprintf("%s...+%d more", s, int(v.Len)-len(s))
|
s = fmt.Sprintf("%s...+%d more", s, int(v.Len)-len(s))
|
||||||
@ -109,21 +110,21 @@ func (v *Variable) writeStringTo(buf *bytes.Buffer) {
|
|||||||
fmt.Fprintf(buf, "%q", s)
|
fmt.Fprintf(buf, "%q", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Variable) writeSliceTo(buf *bytes.Buffer, newlines, includeType bool, indent string) {
|
func (v *Variable) writeSliceTo(buf io.Writer, newlines, includeType bool, indent string) {
|
||||||
if includeType {
|
if includeType {
|
||||||
fmt.Fprintf(buf, "%s len: %d, cap: %d, ", v.Type, v.Len, v.Cap)
|
fmt.Fprintf(buf, "%s len: %d, cap: %d, ", v.Type, v.Len, v.Cap)
|
||||||
}
|
}
|
||||||
v.writeSliceOrArrayTo(buf, newlines, indent)
|
v.writeSliceOrArrayTo(buf, newlines, indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Variable) writeArrayTo(buf *bytes.Buffer, newlines, includeType bool, indent string) {
|
func (v *Variable) writeArrayTo(buf io.Writer, newlines, includeType bool, indent string) {
|
||||||
if includeType {
|
if includeType {
|
||||||
fmt.Fprintf(buf, "%s ", v.Type)
|
fmt.Fprintf(buf, "%s ", v.Type)
|
||||||
}
|
}
|
||||||
v.writeSliceOrArrayTo(buf, newlines, indent)
|
v.writeSliceOrArrayTo(buf, newlines, indent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Variable) writeStructTo(buf *bytes.Buffer, newlines, includeType bool, indent string) {
|
func (v *Variable) writeStructTo(buf io.Writer, newlines, includeType bool, indent string) {
|
||||||
if int(v.Len) != len(v.Children) {
|
if int(v.Len) != len(v.Children) {
|
||||||
fmt.Fprintf(buf, "(*%s)(0x%x)", v.Type, v.Addr)
|
fmt.Fprintf(buf, "(*%s)(0x%x)", v.Type, v.Addr)
|
||||||
return
|
return
|
||||||
@ -157,7 +158,7 @@ func (v *Variable) writeStructTo(buf *bytes.Buffer, newlines, includeType bool,
|
|||||||
fmt.Fprintf(buf, "}")
|
fmt.Fprintf(buf, "}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Variable) writeMapTo(buf *bytes.Buffer, newlines, includeType bool, indent string) {
|
func (v *Variable) writeMapTo(buf io.Writer, newlines, includeType bool, indent string) {
|
||||||
if includeType {
|
if includeType {
|
||||||
fmt.Fprintf(buf, "%s ", v.Type)
|
fmt.Fprintf(buf, "%s ", v.Type)
|
||||||
}
|
}
|
||||||
@ -261,7 +262,7 @@ func (v *Variable) shouldNewlineStruct(newlines bool) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Variable) writeSliceOrArrayTo(buf *bytes.Buffer, newlines bool, indent string) {
|
func (v *Variable) writeSliceOrArrayTo(buf io.Writer, newlines bool, indent string) {
|
||||||
nl := v.shouldNewlineArray(newlines)
|
nl := v.shouldNewlineArray(newlines)
|
||||||
fmt.Fprintf(buf, "[")
|
fmt.Fprintf(buf, "[")
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,11 @@ package api
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/derekparker/delve/proc"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/derekparker/delve/proc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DebuggerState represents the current context of the debugger.
|
// DebuggerState represents the current context of the debugger.
|
||||||
@ -46,10 +47,10 @@ type Breakpoint struct {
|
|||||||
|
|
||||||
// tracepoint flag
|
// tracepoint flag
|
||||||
Tracepoint bool `json:"continue"`
|
Tracepoint bool `json:"continue"`
|
||||||
// number of stack frames to retrieve
|
|
||||||
Stacktrace int `json:"stacktrace"`
|
|
||||||
// retrieve goroutine information
|
// retrieve goroutine information
|
||||||
Goroutine bool `json:"goroutine"`
|
Goroutine bool `json:"goroutine"`
|
||||||
|
// number of stack frames to retrieve
|
||||||
|
Stacktrace int `json:"stacktrace"`
|
||||||
// variables to evaluate
|
// variables to evaluate
|
||||||
Variables []string `json:"variables,omitempty"`
|
Variables []string `json:"variables,omitempty"`
|
||||||
// number of times a breakpoint has been reached in a certain goroutine
|
// number of times a breakpoint has been reached in a certain goroutine
|
||||||
|
|||||||
@ -311,7 +311,7 @@ func (c *Commands) goroutine(t *Term, ctx callContext, argstr string) error {
|
|||||||
}
|
}
|
||||||
if args[0] == "" {
|
if args[0] == "" {
|
||||||
return printscope(t)
|
return printscope(t)
|
||||||
} else {
|
}
|
||||||
gid, err := strconv.Atoi(argstr)
|
gid, err := strconv.Atoi(argstr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -328,7 +328,6 @@ func (c *Commands) goroutine(t *Term, ctx callContext, argstr string) error {
|
|||||||
|
|
||||||
fmt.Printf("Switched from %d to %d (thread %d)\n", oldState.SelectedGoroutine.ID, gid, newState.CurrentThread.ID)
|
fmt.Printf("Switched from %d to %d (thread %d)\n", oldState.SelectedGoroutine.ID, gid, newState.CurrentThread.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
|
||||||
case 2:
|
case 2:
|
||||||
args = append(args, "")
|
args = append(args, "")
|
||||||
}
|
}
|
||||||
@ -345,8 +344,6 @@ func (c *Commands) goroutine(t *Term, ctx callContext, argstr string) error {
|
|||||||
func (c *Commands) frame(t *Term, ctx callContext, args string) error {
|
func (c *Commands) frame(t *Term, ctx callContext, args string) error {
|
||||||
v := strings.SplitN(args, " ", 3)
|
v := strings.SplitN(args, " ", 3)
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
switch len(v) {
|
switch len(v) {
|
||||||
case 0, 1:
|
case 0, 1:
|
||||||
return errors.New("not enough arguments")
|
return errors.New("not enough arguments")
|
||||||
@ -354,6 +351,7 @@ func (c *Commands) frame(t *Term, ctx callContext, args string) error {
|
|||||||
v = append(v, "")
|
v = append(v, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
ctx.Prefix = scopePrefix
|
ctx.Prefix = scopePrefix
|
||||||
ctx.Scope.Frame, err = strconv.Atoi(v[0])
|
ctx.Scope.Frame, err = strconv.Atoi(v[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -592,7 +590,7 @@ func setBreakpoint(t *Term, tracepoint bool, argstr string) error {
|
|||||||
requestedBp.Name = ""
|
requestedBp.Name = ""
|
||||||
locspec = argstr
|
locspec = argstr
|
||||||
var err2 error
|
var err2 error
|
||||||
locs, err2 = t.client.FindLocation(api.EvalScope{-1, 0}, locspec)
|
locs, err2 = t.client.FindLocation(api.EvalScope{GoroutineID: -1, Frame: 0}, locspec)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1051,13 +1049,11 @@ func exitCommand(t *Term, ctx callContext, args string) error {
|
|||||||
return ExitRequestError{}
|
return ExitRequestError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBreakpointByIDOrName(t *Term, arg string) (bp *api.Breakpoint, err error) {
|
func getBreakpointByIDOrName(t *Term, arg string) (*api.Breakpoint, error) {
|
||||||
if id, err := strconv.Atoi(arg); err == nil {
|
if id, err := strconv.Atoi(arg); err == nil {
|
||||||
bp, err = t.client.GetBreakpoint(id)
|
return t.client.GetBreakpoint(id)
|
||||||
} else {
|
|
||||||
bp, err = t.client.GetBreakpointByName(arg)
|
|
||||||
}
|
}
|
||||||
return
|
return t.client.GetBreakpointByName(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) onCmd(t *Term, ctx callContext, argstr string) error {
|
func (c *Commands) onCmd(t *Term, ctx callContext, argstr string) error {
|
||||||
@ -1154,7 +1150,6 @@ func formatBreakpointLocation(bp *api.Breakpoint) string {
|
|||||||
p := ShortenFilePath(bp.File)
|
p := ShortenFilePath(bp.File)
|
||||||
if bp.FunctionName != "" {
|
if bp.FunctionName != "" {
|
||||||
return fmt.Sprintf("%#v for %s() %s:%d", bp.Addr, bp.FunctionName, p, bp.Line)
|
return fmt.Sprintf("%#v for %s() %s:%d", bp.Addr, bp.FunctionName, p, bp.Line)
|
||||||
} else {
|
}
|
||||||
return fmt.Sprintf("%#v for %s:%d", bp.Addr, p, bp.Line)
|
return fmt.Sprintf("%#v for %s:%d", bp.Addr, p, bp.Line)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -102,7 +102,6 @@ func (t *Term) Run() (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var status int
|
|
||||||
for {
|
for {
|
||||||
cmdstr, err := t.promptForInput()
|
cmdstr, err := t.promptForInput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -110,8 +109,7 @@ func (t *Term) Run() (int, error) {
|
|||||||
fmt.Println("exit")
|
fmt.Println("exit")
|
||||||
return t.handleExit()
|
return t.handleExit()
|
||||||
}
|
}
|
||||||
err, status = fmt.Errorf("Prompt for input failed.\n"), 1
|
return 1, fmt.Errorf("Prompt for input failed.\n")
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdstr, args := parseCommand(cmdstr)
|
cmdstr, args := parseCommand(cmdstr)
|
||||||
@ -129,8 +127,6 @@ func (t *Term) Run() (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Println prints a line to the terminal.
|
// Println prints a line to the terminal.
|
||||||
@ -161,7 +157,7 @@ func (t *Term) handleExit() (int, error) {
|
|||||||
fmt.Println("Error saving history file: ", err)
|
fmt.Println("Error saving history file: ", err)
|
||||||
} else {
|
} else {
|
||||||
if f, err := os.OpenFile(fullHistoryFile, os.O_RDWR, 0666); err == nil {
|
if f, err := os.OpenFile(fullHistoryFile, os.O_RDWR, 0666); err == nil {
|
||||||
_, err := t.line.WriteHistory(f)
|
_, err = t.line.WriteHistory(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("readline history error: ", err)
|
fmt.Println("readline history error: ", err)
|
||||||
}
|
}
|
||||||
@ -183,8 +179,7 @@ func (t *Term) handleExit() (int, error) {
|
|||||||
answer = strings.ToLower(strings.TrimSpace(answer))
|
answer = strings.ToLower(strings.TrimSpace(answer))
|
||||||
kill = (answer != "n" && answer != "no")
|
kill = (answer != "n" && answer != "no")
|
||||||
}
|
}
|
||||||
err = t.client.Detach(kill)
|
if err := t.client.Detach(kill); err != nil {
|
||||||
if err != nil {
|
|
||||||
return 1, err
|
return 1, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user