-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
gobuild.go
132 lines (117 loc) · 4.07 KB
/
gobuild.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Package gobuild provides utilities for building programs and tests
// for the debugging session.
package gobuild
import (
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"time"
"github.com/go-delve/delve/pkg/config"
)
// Remove the file at path and issue a warning to stderr if this fails.
// This can be used to remove the temporary binary generated for the session.
func Remove(path string) {
var err error
for i := 0; i < 20; i++ {
err = os.Remove(path)
// Open files can be removed on Unix, but not on Windows, where there also appears
// to be a delay in releasing the binary when the process exits.
// Leaving temporary files behind can be annoying to users, so we try again.
if err == nil || runtime.GOOS != "windows" {
break
}
time.Sleep(1 * time.Millisecond)
}
if err != nil {
fmt.Fprintf(os.Stderr, "could not remove %v: %v\n", path, err)
}
}
// GoBuild builds non-test files in 'pkgs' with the specified 'buildflags'
// and writes the output at 'debugname'.
func GoBuild(debugname string, pkgs []string, buildflags string) error {
args := goBuildArgs(debugname, pkgs, buildflags, false)
return gocommandRun("build", args...)
}
// GoBuildCombinedOutput builds non-test files in 'pkgs' with the specified 'buildflags'
// and writes the output at 'debugname'.
func GoBuildCombinedOutput(debugname string, pkgs []string, buildflags interface{}) (string, []byte, error) {
args, err := goBuildArgs2(debugname, pkgs, buildflags, false)
if err != nil {
return "", nil, err
}
return gocommandCombinedOutput("build", args...)
}
// GoTestBuild builds test files 'pkgs' with the specified 'buildflags'
// and writes the output at 'debugname'.
func GoTestBuild(debugname string, pkgs []string, buildflags string) error {
args := goBuildArgs(debugname, pkgs, buildflags, true)
return gocommandRun("test", args...)
}
// GoTestBuildCombinedOutput builds test files 'pkgs' with the specified 'buildflags'
// and writes the output at 'debugname'.
func GoTestBuildCombinedOutput(debugname string, pkgs []string, buildflags interface{}) (string, []byte, error) {
args, err := goBuildArgs2(debugname, pkgs, buildflags, true)
if err != nil {
return "", nil, err
}
return gocommandCombinedOutput("test", args...)
}
func goBuildArgs(debugname string, pkgs []string, buildflags string, isTest bool) []string {
var args []string
bfv := config.SplitQuotedFields(buildflags, '\'')
if len(bfv) >= 2 && bfv[0] == "-C" {
args = append(args, bfv[:2]...)
bfv = bfv[2:]
} else if len(bfv) >= 1 && strings.HasPrefix(bfv[0], "-C=") {
args = append(args, bfv[0])
bfv = bfv[1:]
}
args = append(args, "-o", debugname)
if isTest {
args = append([]string{"-c"}, args...)
}
args = append(args, "-gcflags", "all=-N -l")
if buildflags != "" {
args = append(args, bfv...)
}
args = append(args, pkgs...)
return args
}
// goBuildArgs2 is like goBuildArgs, but takes either string or []string.
func goBuildArgs2(debugname string, pkgs []string, buildflags interface{}, isTest bool) ([]string, error) {
var args []string
switch buildflags := buildflags.(type) {
case string:
return goBuildArgs(debugname, pkgs, buildflags, isTest), nil
case nil:
case []string:
args = append(args, buildflags...)
default:
return nil, fmt.Errorf("invalid buildflags type %T", buildflags)
}
args = append(args, "-o", debugname)
if isTest {
args = append([]string{"-c"}, args...)
}
args = append(args, "-gcflags", "all=-N -l")
return append(args, pkgs...), nil
}
func gocommandRun(command string, args ...string) error {
_, goBuild := gocommandExecCmd(command, args...)
goBuild.Stderr = os.Stdout
goBuild.Stdout = os.Stderr
return goBuild.Run()
}
func gocommandCombinedOutput(command string, args ...string) (string, []byte, error) {
buildCmd, goBuild := gocommandExecCmd(command, args...)
out, err := goBuild.CombinedOutput()
return buildCmd, out, err
}
func gocommandExecCmd(command string, args ...string) (string, *exec.Cmd) {
allargs := []string{command}
allargs = append(allargs, args...)
goBuild := exec.Command("go", allargs...)
return strings.Join(append([]string{"go"}, allargs...), " "), goBuild
}