dlv: bugfix: Allow quoting in build flags argument (#639)
Allows quoted substrings in build-flags flag. This fixes a build problem on windows where the default build flags must contain a space. Fixes #634 and #638
This commit is contained in:
parent
4d8daeb1a8
commit
5d78c04e62
7
_fixtures/buildtest/main.go
Normal file
7
_fixtures/buildtest/main.go
Normal file
@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("hello world!")
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package cmds
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
@ -10,8 +11,8 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unicode"
|
||||
|
||||
"github.com/derekparker/delve/config"
|
||||
"github.com/derekparker/delve/service"
|
||||
@ -68,7 +69,7 @@ func New() *cobra.Command {
|
||||
buildFlagsDefault := ""
|
||||
if runtime.GOOS == "windows" {
|
||||
// Work-around for https://github.com/golang/go/issues/13154
|
||||
buildFlagsDefault = "-ldflags=-linkmode internal"
|
||||
buildFlagsDefault = "-ldflags='-linkmode internal'"
|
||||
}
|
||||
|
||||
// Main dlv root command.
|
||||
@ -447,7 +448,7 @@ func execute(attachPid int, processArgs []string, conf *config.Config, kind exec
|
||||
func gobuild(debugname, pkg string) error {
|
||||
args := []string{"-gcflags", "-N -l", "-o", debugname}
|
||||
if BuildFlags != "" {
|
||||
args = append(args, strings.Fields(BuildFlags)...)
|
||||
args = append(args, splitQuotedFields(BuildFlags)...)
|
||||
}
|
||||
args = append(args, pkg)
|
||||
return gocommand("build", args...)
|
||||
@ -456,7 +457,7 @@ func gobuild(debugname, pkg string) error {
|
||||
func gotestbuild(pkg string) error {
|
||||
args := []string{"-gcflags", "-N -l", "-c", "-o", testdebugname}
|
||||
if BuildFlags != "" {
|
||||
args = append(args, strings.Fields(BuildFlags)...)
|
||||
args = append(args, splitQuotedFields(BuildFlags)...)
|
||||
}
|
||||
args = append(args, pkg)
|
||||
return gocommand("test", args...)
|
||||
@ -469,3 +470,60 @@ func gocommand(command string, args ...string) error {
|
||||
goBuild.Stderr = os.Stderr
|
||||
return goBuild.Run()
|
||||
}
|
||||
|
||||
// Like strings.Fields but ignores spaces inside areas surrounded
|
||||
// by single quotes.
|
||||
// To specify a single quote use backslash to escape it: '\''
|
||||
func splitQuotedFields(in string) []string {
|
||||
type stateEnum int
|
||||
const (
|
||||
inSpace stateEnum = iota
|
||||
inField
|
||||
inQuote
|
||||
inQuoteEscaped
|
||||
)
|
||||
state := inSpace
|
||||
r := []string{}
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, ch := range in {
|
||||
switch state {
|
||||
case inSpace:
|
||||
if ch == '\'' {
|
||||
state = inQuote
|
||||
} else if !unicode.IsSpace(ch) {
|
||||
buf.WriteRune(ch)
|
||||
state = inField
|
||||
}
|
||||
|
||||
case inField:
|
||||
if ch == '\'' {
|
||||
state = inQuote
|
||||
} else if unicode.IsSpace(ch) {
|
||||
r = append(r, buf.String())
|
||||
buf.Reset()
|
||||
} else {
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
|
||||
case inQuote:
|
||||
if ch == '\'' {
|
||||
state = inField
|
||||
} else if ch == '\\' {
|
||||
state = inQuoteEscaped
|
||||
} else {
|
||||
buf.WriteRune(ch)
|
||||
}
|
||||
|
||||
case inQuoteEscaped:
|
||||
buf.WriteRune(ch)
|
||||
state = inQuote
|
||||
}
|
||||
}
|
||||
|
||||
if buf.Len() != 0 {
|
||||
r = append(r, buf.String())
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
21
cmd/dlv/cmds/commands_test.go
Normal file
21
cmd/dlv/cmds/commands_test.go
Normal file
@ -0,0 +1,21 @@
|
||||
package cmds
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSplitQuotedFields(t *testing.T) {
|
||||
in := `field'A' 'fieldB' fie'l\'d'C fieldD 'another field' fieldE`
|
||||
tgt := []string{"fieldA", "fieldB", "fiel'dC", "fieldD", "another field", "fieldE"}
|
||||
out := splitQuotedFields(in)
|
||||
|
||||
if len(tgt) != len(out) {
|
||||
t.Fatalf("expected %#v, got %#v (len mismatch)", tgt, out)
|
||||
}
|
||||
|
||||
for i := range tgt {
|
||||
if tgt[i] != out[i] {
|
||||
t.Fatalf(" expected %#v, got %#v (mismatch at %d)", tgt, out, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
61
cmd/dlv/dlv_test.go
Normal file
61
cmd/dlv/dlv_test.go
Normal file
@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
protest "github.com/derekparker/delve/proc/test"
|
||||
"github.com/derekparker/delve/service/rpc2"
|
||||
)
|
||||
|
||||
func assertNoError(err error, t testing.TB, s string) {
|
||||
if err != nil {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
fname := filepath.Base(file)
|
||||
t.Fatalf("failed assertion at %s:%d: %s - %s\n", fname, line, s, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
const listenAddr = "localhost:40573"
|
||||
cmd := exec.Command("go", "build", "github.com/derekparker/delve/cmd/dlv")
|
||||
assertNoError(cmd.Run(), t, "go build")
|
||||
wd, _ := os.Getwd()
|
||||
dlvbin := filepath.Join(wd, "dlv")
|
||||
|
||||
defer os.Remove(dlvbin)
|
||||
|
||||
fixtures := protest.FindFixturesDir()
|
||||
|
||||
buildtestdir := filepath.Join(fixtures, "buildtest")
|
||||
|
||||
cmd = exec.Command(dlvbin, "debug", "--headless=true", "--listen="+listenAddr, "--api-version=2")
|
||||
cmd.Dir = buildtestdir
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
assertNoError(err, t, "stdout pipe")
|
||||
cmd.Start()
|
||||
defer func() {
|
||||
cmd.Process.Signal(os.Interrupt)
|
||||
cmd.Wait()
|
||||
}()
|
||||
|
||||
scan := bufio.NewScanner(stdout)
|
||||
// wait for the debugger to start
|
||||
scan.Scan()
|
||||
go func() {
|
||||
for scan.Scan() {
|
||||
// keep pipe empty
|
||||
}
|
||||
}()
|
||||
|
||||
client := rpc2.NewClient(listenAddr)
|
||||
state := <-client.Continue()
|
||||
|
||||
if !state.Exited {
|
||||
t.Fatal("Program did not exit")
|
||||
}
|
||||
}
|
||||
@ -13,8 +13,8 @@ import (
|
||||
"github.com/derekparker/delve/proc/test"
|
||||
"github.com/derekparker/delve/service"
|
||||
"github.com/derekparker/delve/service/api"
|
||||
"github.com/derekparker/delve/service/rpccommon"
|
||||
"github.com/derekparker/delve/service/rpc2"
|
||||
"github.com/derekparker/delve/service/rpccommon"
|
||||
)
|
||||
|
||||
type FakeTerminal struct {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user