Source file src/cmd/go/scriptcmds_test.go

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main_test
     6  
     7  import (
     8  	"cmd/go/internal/script"
     9  	"cmd/go/internal/script/scripttest"
    10  	"cmd/go/internal/work"
    11  	"errors"
    12  	"fmt"
    13  	"os"
    14  	"os/exec"
    15  	"strings"
    16  	"sync"
    17  	"time"
    18  )
    19  
    20  func scriptCommands(interrupt os.Signal, waitDelay time.Duration) map[string]script.Cmd {
    21  	cmds := scripttest.DefaultCmds()
    22  
    23  	// Customize the "exec" interrupt signal and grace period.
    24  	var cancel func(cmd *exec.Cmd) error
    25  	if interrupt != nil {
    26  		cancel = func(cmd *exec.Cmd) error {
    27  			return cmd.Process.Signal(interrupt)
    28  		}
    29  	}
    30  
    31  	cmdExec := script.Exec(cancel, waitDelay)
    32  	cmds["exec"] = cmdExec
    33  
    34  	add := func(name string, cmd script.Cmd) {
    35  		if _, ok := cmds[name]; ok {
    36  			panic(fmt.Sprintf("command %q is already registered", name))
    37  		}
    38  		cmds[name] = cmd
    39  	}
    40  
    41  	add("cc", scriptCC(cmdExec))
    42  	cmdGo := scriptGo(cancel, waitDelay)
    43  	add("go", cmdGo)
    44  	add("stale", scriptStale(cmdGo))
    45  
    46  	return cmds
    47  }
    48  
    49  // scriptCC runs the C compiler along with platform specific options.
    50  func scriptCC(cmdExec script.Cmd) script.Cmd {
    51  	return script.Command(
    52  		script.CmdUsage{
    53  			Summary: "run the platform C compiler",
    54  			Args:    "args...",
    55  		},
    56  		func(s *script.State, args ...string) (script.WaitFunc, error) {
    57  			b := work.NewBuilder(s.Getwd())
    58  			wait, err := cmdExec.Run(s, append(b.GccCmd(".", ""), args...)...)
    59  			if err != nil {
    60  				return wait, err
    61  			}
    62  			waitAndClean := func(s *script.State) (stdout, stderr string, err error) {
    63  				stdout, stderr, err = wait(s)
    64  				if closeErr := b.Close(); err == nil {
    65  					err = closeErr
    66  				}
    67  				return stdout, stderr, err
    68  			}
    69  			return waitAndClean, nil
    70  		})
    71  }
    72  
    73  var scriptGoInvoked sync.Map // testing.TB → go command was invoked
    74  
    75  // scriptGo runs the go command.
    76  func scriptGo(cancel func(*exec.Cmd) error, waitDelay time.Duration) script.Cmd {
    77  	cmd := script.Program(testGo, cancel, waitDelay)
    78  	// Inject code to update scriptGoInvoked before invoking the Go command.
    79  	return script.Command(*cmd.Usage(), func(state *script.State, s ...string) (script.WaitFunc, error) {
    80  		t, ok := tbFromContext(state.Context())
    81  		if !ok {
    82  			return nil, errors.New("script Context unexpectedly missing testing.TB key")
    83  		}
    84  		_, dup := scriptGoInvoked.LoadOrStore(t, true)
    85  		if !dup {
    86  			t.Cleanup(func() { scriptGoInvoked.Delete(t) })
    87  		}
    88  		return cmd.Run(state, s...)
    89  	})
    90  }
    91  
    92  // scriptStale checks that the named build targets are stale.
    93  func scriptStale(cmdGo script.Cmd) script.Cmd {
    94  	return script.Command(
    95  		script.CmdUsage{
    96  			Summary: "check that build targets are stale",
    97  			Args:    "target...",
    98  		},
    99  		func(s *script.State, args ...string) (script.WaitFunc, error) {
   100  			if len(args) == 0 {
   101  				return nil, script.ErrUsage
   102  			}
   103  			tmpl := "{{if .Error}}{{.ImportPath}}: {{.Error.Err}}" +
   104  				"{{else}}{{if not .Stale}}{{.ImportPath}} ({{.Target}}) is not stale{{end}}" +
   105  				"{{end}}"
   106  
   107  			wait, err := cmdGo.Run(s, append([]string{"list", "-e", "-f=" + tmpl}, args...)...)
   108  			if err != nil {
   109  				return nil, err
   110  			}
   111  
   112  			stdout, stderr, err := wait(s)
   113  			if len(stderr) != 0 {
   114  				s.Logf("%s", stderr)
   115  			}
   116  			if err != nil {
   117  				return nil, err
   118  			}
   119  			if out := strings.TrimSpace(stdout); out != "" {
   120  				return nil, errors.New(out)
   121  			}
   122  			return nil, nil
   123  		})
   124  }
   125  

View as plain text