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  }