gitlab.com/polyapp-open-source/poly@v0.0.0-20200304172929-90b164ae7520/cmd/build.go (about)

     1  package cmd
     2  
     3  import (
     4  	"os"
     5  	"os/exec"
     6  	"path/filepath"
     7  
     8  	"github.com/spf13/cobra"
     9  )
    10  
    11  // buildCmd represents the build command
    12  //nolint
    13  var buildCmd = &cobra.Command{
    14  	Use:   "build",
    15  	Short: "Runs go build across all main.go files",
    16  	Long: `Runs 'go list' to get a list of packages and then runs 'go build'
    17  across each package individually with standard & GOOS=js GOARCH=wasm environments.
    18  If GOOS=js GOARCH=wasm it builds the file and deposits it in ./public or
    19  any other directory specified by the WASMOut parameter with the .wasm file extension.
    20  If tinygo is installed it is used when GOOS=js GOARCH=wasm and the result is saved
    21  as buildname_tinygo.wasm alongside the 'go build' output, buildname.wasm
    22  GOOS=js and GOARCH=wasm makes an effort to not build code which could rely on non-js syscalls.
    23  Results are collected and printed one after the other. Example output:
    24  
    25  gledr@LAPTOP-AH6IAHBO MINGW64 ~/Polyapp_Apps/gocode/src/gitlab.com/polyapp-open-source/poly/testdata (CI-expansion)
    26  $ poly build
    27  ----- Command: C:\Go\bin\go.exe build -o C:\Users\gledr\Polyapp_Apps\gocode\src\gitlab.com\polyapp-open-source\poly\testdata\cmd\cmd.exe gitlab.com/polyapp-open-source/poly/testdata/cmd ----- GOOS: windows GOARCH:  -----
    28  ----- Command: C:\Go\bin\go.exe build -o C:\Users\gledr\Polyapp_Apps\gocode\src\gitlab.com\polyapp-open-source\poly\testdata\cmd\hello\hello.exe gitlab.com/polyapp-open-source/poly/testdata/cmd/hello ----- GOOS: windows GOARCH:  -----
    29  ----- Command: C:\Go\bin\go.exe build -ldflags=-s -w -o C:\Users\gledr\Polyapp_Apps\gocode\src\gitlab.com\polyapp-open-source\poly\testdata\cmd\wasm1\wasm1.wasm gitlab.com/polyapp-open-source/poly/testdata/cmd/wasm1 ----- GOOS: js GOARCH: wasm -----
    30  ----- Command: C:\Go\bin\go.exe build -ldflags=-s -w -o C:\Users\gledr\Polyapp_Apps\gocode\src\gitlab.com\polyapp-open-source\poly\testdata\cmd\wasm2\wasm2.wasm gitlab.com/polyapp-open-source/poly/testdata/cmd/wasm2 ----- GOOS: js GOARCH: wasm -----
    31  ----- Command: C:\Go\bin\go.exe build -ldflags=-s -w -o C:\Users\gledr\Polyapp_Apps\gocode\src\gitlab.com\polyapp-open-source\poly\testdata\cmd\wasm3\wasm3.wasm gitlab.com/polyapp-open-source/poly/testdata/cmd/wasm3 ----- GOOS: js GOARCH: wasm -----
    32  
    33  `,
    34  	Run: func(cmd *cobra.Command, args []string) {
    35  		exitCode := Build(cmd.Flag("WASMOut").Value.String())
    36  		os.Exit(exitCode)
    37  	},
    38  }
    39  
    40  func init() {
    41  	rootCmd.AddCommand(buildCmd)
    42  	buildCmd.Flags().String("WASMOut", "./public", "Place all compiled WASM binaries into this relative directory")
    43  }
    44  
    45  // Build performs the work of 'poly build'.
    46  func Build(WASMOut string) (exitCode int) { //nolint
    47  	defaultPaths, JSWASMPaths := GetTargets()
    48  
    49  	defaultProcs := startDefaultBuild(defaultPaths)
    50  
    51  	JSWASMProcs := startWASMBuild(JSWASMPaths, WASMOut)
    52  
    53  	largestExitCode := 0
    54  	largestDefaultExitCode := waitAndResolveDefaultBuilds(defaultProcs)
    55  	if largestDefaultExitCode > largestExitCode {
    56  		largestExitCode = largestDefaultExitCode
    57  	}
    58  	largestWASMExitCode := waitAndResolveWASMBuilds(JSWASMProcs, JSWASMPaths)
    59  	if largestWASMExitCode > largestExitCode {
    60  		largestExitCode = largestWASMExitCode
    61  	}
    62  
    63  	return largestExitCode
    64  }
    65  
    66  // startWASMBuild spawns some processes to being a WASM build.
    67  // We try to compile with both tinygo and regular 'go build' every time.
    68  func startWASMBuild(JSWASMPaths []string, wasmOutPath string) (JSWASMProcs []*procInfo) { //nolint
    69  	JSWASMProcs = make([]*procInfo, len(JSWASMPaths)*2)
    70  	for i, targetPath := range JSWASMPaths {
    71  		var outputPath string
    72  		if wasmOutPath == "" {
    73  			outputPath = filepath.Join(ListPathToAbsPath(targetPath), GetOutputFileName(targetPath, regularGoWASM))
    74  		} else {
    75  			outputPath = filepath.Join(ListPathToAbsPath(wasmOutPath), GetOutputFileName(targetPath, regularGoWASM))
    76  		}
    77  		JSWASMProc := procInfo{
    78  			Cmd: exec.Command("go", "build", "-ldflags=-s -w", "-o", outputPath, targetPath),
    79  		}
    80  		JSWASMProc.Cmd.Env = append(os.Environ(), "GOOS=js", "GOARCH=wasm")
    81  		JSWASMProc.Cmd.Stdout = &JSWASMProc.Stdout
    82  		JSWASMProc.Cmd.Stderr = &JSWASMProc.Stderr
    83  		JSWASMProc.StartError = JSWASMProc.Cmd.Start()
    84  		JSWASMProcs[i] = &JSWASMProc
    85  	}
    86  	for i, targetPath := range JSWASMPaths {
    87  		var outputPath string
    88  		if wasmOutPath == "" {
    89  			outputPath = filepath.Join(ListPathToAbsPath(targetPath), GetOutputFileName(targetPath, tinygoWASM))
    90  		} else {
    91  			outputPath = filepath.Join(ListPathToAbsPath(wasmOutPath), GetOutputFileName(targetPath, tinygoWASM))
    92  		}
    93  		JSWASMProc := procInfo{
    94  			Cmd: exec.Command("tinygo", "build", "-o", outputPath, "-target", "wasm", targetPath),
    95  		}
    96  		JSWASMProc.Cmd.Stdout = &JSWASMProc.Stdout
    97  		JSWASMProc.Cmd.Stderr = &JSWASMProc.Stderr
    98  		JSWASMProc.StartError = JSWASMProc.Cmd.Start()
    99  		JSWASMProcs[i+len(JSWASMPaths)] = &JSWASMProc
   100  	}
   101  	return JSWASMProcs
   102  }
   103  
   104  func startDefaultBuild(defaultPaths []string) (defaultProcs []*procInfo) {
   105  	defaultProcs = make([]*procInfo, len(defaultPaths))
   106  	for i, targetPath := range defaultPaths {
   107  		outputPath := filepath.Join(ListPathToAbsPath(targetPath), GetOutputFileName(targetPath, notWASM))
   108  		defaultProc := procInfo{
   109  			Cmd: exec.Command("go", "build", "-o", outputPath, targetPath),
   110  		}
   111  		defaultProc.Cmd.Stdout = &defaultProc.Stdout
   112  		defaultProc.Cmd.Stderr = &defaultProc.Stderr
   113  		defaultProc.StartError = defaultProc.Cmd.Start()
   114  		defaultProcs[i] = &defaultProc
   115  	}
   116  	return defaultProcs
   117  }
   118  
   119  // waitAndResolveWASMBuilds waits for the tinygo and regular 'go build' WASM builds.
   120  // this function ignores tinygo errors when computing largestExitCode.
   121  func waitAndResolveWASMBuilds(JSWASMProcs []*procInfo, JSWASMPaths []string) (largestExitCode int) { //nolint
   122  	largestExitCode = 0
   123  	for i, proc := range JSWASMProcs {
   124  		proc.WaitError = proc.Cmd.Wait()
   125  		proc.print()
   126  		osExitValue := proc.getExitValue()
   127  		if i < len(JSWASMPaths) {
   128  			// go build
   129  			if osExitValue > largestExitCode {
   130  				largestExitCode = osExitValue
   131  			}
   132  		}
   133  		// else tinygo build - don't report tinygo's exit code since tinygo need not be installed for build to succeed
   134  	}
   135  	return largestExitCode
   136  }
   137  
   138  // waitAndResolveDefaultBuilds waits for the default builds to finish and reports the largest exit code.
   139  func waitAndResolveDefaultBuilds(defaultProcs []*procInfo) (largestExitCode int) { //nolint
   140  	for _, proc := range defaultProcs {
   141  		proc.WaitError = proc.Cmd.Wait()
   142  		proc.print()
   143  		osExitValue := proc.getExitValue()
   144  		if osExitValue > largestExitCode {
   145  			largestExitCode = osExitValue
   146  		}
   147  	}
   148  	return largestExitCode
   149  }