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