kosx

Google cmd exec.go

Dec 30th, 2020
1,478
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Copyright 2009 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 exec runs external commands. It wraps os.StartProcess to make it
  6. // easier to remap stdin and stdout, connect I/O with pipes, and do other
  7. // adjustments.
  8. //
  9. // Unlike the "system" library call from C and other languages, the
  10. // os/exec package intentionally does not invoke the system shell and
  11. // does not expand any glob patterns or handle other expansions,
  12. // pipelines, or redirections typically done by shells. The package
  13. // behaves more like C's "exec" family of functions. To expand glob
  14. // patterns, either call the shell directly, taking care to escape any
  15. // dangerous input, or use the path/filepath package's Glob function.
  16. // To expand environment variables, use package os's ExpandEnv.
  17. //
  18. // Note that the examples in this package assume a Unix system.
  19. // They may not run on Windows, and they do not run in the Go Playground
  20. // used by golang.org and godoc.org.
  21. package exec
  22.  
  23. import (
  24.     "bytes"
  25.     "context"
  26.     "errors"
  27.     "internal/syscall/execenv"
  28.     "io"
  29.     "os"
  30.     "path/filepath"
  31.     "runtime"
  32.     "strconv"
  33.     "strings"
  34.     "sync"
  35.     "syscall"
  36. )
  37.  
  38. // Error is returned by LookPath when it fails to classify a file as an
  39. // executable.
  40. type Error struct {
  41.     // Name is the file name for which the error occurred.
  42.     Name string
  43.     // Err is the underlying error.
  44.     Err error
  45. }
  46.  
  47. func (e *Error) Error() string {
  48.     return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error()
  49. }
  50.  
  51. func (e *Error) Unwrap() error { return e.Err }
  52.  
  53. // Cmd represents an external command being prepared or run.
  54. //
  55. // A Cmd cannot be reused after calling its Run, Output or CombinedOutput
  56. // methods.
  57. type Cmd struct {
  58.     // Path is the path of the command to run.
  59.     //
  60.     // This is the only field that must be set to a non-zero
  61.     // value. If Path is relative, it is evaluated relative
  62.     // to Dir.
  63.     Path string
  64.  
  65.     // Args holds command line arguments, including the command as Args[0].
  66.     // If the Args field is empty or nil, Run uses {Path}.
  67.     //
  68.     // In typical use, both Path and Args are set by calling Command.
  69.     Args []string
  70.  
  71.     // Env specifies the environment of the process.
  72.     // Each entry is of the form "key=value".
  73.     // If Env is nil, the new process uses the current process's
  74.     // environment.
  75.     // If Env contains duplicate environment keys, only the last
  76.     // value in the slice for each duplicate key is used.
  77.     // As a special case on Windows, SYSTEMROOT is always added if
  78.     // missing and not explicitly set to the empty string.
  79.     Env []string
  80.  
  81.     // Dir specifies the working directory of the command.
  82.     // If Dir is the empty string, Run runs the command in the
  83.     // calling process's current directory.
  84.     Dir string
  85.  
  86.     // Stdin specifies the process's standard input.
  87.     //
  88.     // If Stdin is nil, the process reads from the null device (os.DevNull).
  89.     //
  90.     // If Stdin is an *os.File, the process's standard input is connected
  91.     // directly to that file.
  92.     //
  93.     // Otherwise, during the execution of the command a separate
  94.     // goroutine reads from Stdin and delivers that data to the command
  95.     // over a pipe. In this case, Wait does not complete until the goroutine
  96.     // stops copying, either because it has reached the end of Stdin
  97.     // (EOF or a read error) or because writing to the pipe returned an error.
  98.     Stdin io.Reader
  99.  
  100.     // Stdout and Stderr specify the process's standard output and error.
  101.     //
  102.     // If either is nil, Run connects the corresponding file descriptor
  103.     // to the null device (os.DevNull).
  104.     //
  105.     // If either is an *os.File, the corresponding output from the process
  106.     // is connected directly to that file.
  107.     //
  108.     // Otherwise, during the execution of the command a separate goroutine
  109.     // reads from the process over a pipe and delivers that data to the
  110.     // corresponding Writer. In this case, Wait does not complete until the
  111.     // goroutine reaches EOF or encounters an error.
  112.     //
  113.     // If Stdout and Stderr are the same writer, and have a type that can
  114.     // be compared with ==, at most one goroutine at a time will call Write.
  115.     Stdout io.Writer
  116.     Stderr io.Writer
  117.  
  118.     // ExtraFiles specifies additional open files to be inherited by the
  119.     // new process. It does not include standard input, standard output, or
  120.     // standard error. If non-nil, entry i becomes file descriptor 3+i.
  121.     //
  122.     // ExtraFiles is not supported on Windows.
  123.     ExtraFiles []*os.File
  124.  
  125.     // SysProcAttr holds optional, operating system-specific attributes.
  126.     // Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
  127.     SysProcAttr *syscall.SysProcAttr
  128.  
  129.     // Process is the underlying process, once started.
  130.     Process *os.Process
  131.  
  132.     // ProcessState contains information about an exited process,
  133.     // available after a call to Wait or Run.
  134.     ProcessState *os.ProcessState
  135.  
  136.     ctx             context.Context // nil means none
  137.     lookPathErr     error           // LookPath error, if any.
  138.     finished        bool            // when Wait was called
  139.     childFiles      []*os.File
  140.     closeAfterStart []io.Closer
  141.     closeAfterWait  []io.Closer
  142.     goroutine       []func() error
  143.     errch           chan error // one send per goroutine
  144.     waitDone        chan struct{}
  145. }
  146.  
  147. // Command returns the Cmd struct to execute the named program with
  148. // the given arguments.
  149. //
  150. // It sets only the Path and Args in the returned structure.
  151. //
  152. // If name contains no path separators, Command uses LookPath to
  153. // resolve name to a complete path if possible. Otherwise it uses name
  154. // directly as Path.
  155. //
  156. // The returned Cmd's Args field is constructed from the command name
  157. // followed by the elements of arg, so arg should not include the
  158. // command name itself. For example, Command("echo", "hello").
  159. // Args[0] is always name, not the possibly resolved Path.
  160. //
  161. // On Windows, processes receive the whole command line as a single string
  162. // and do their own parsing. Command combines and quotes Args into a command
  163. // line string with an algorithm compatible with applications using
  164. // CommandLineToArgvW (which is the most common way). Notable exceptions are
  165. // msiexec.exe and cmd.exe (and thus, all batch files), which have a different
  166. // unquoting algorithm. In these or other similar cases, you can do the
  167. // quoting yourself and provide the full command line in SysProcAttr.CmdLine,
  168. // leaving Args empty.
  169. func Command(name string, arg ...string) *Cmd {
  170.     cmd := &Cmd{
  171.         Path: name,
  172.         Args: append([]string{name}, arg...),
  173.     }
  174.     if filepath.Base(name) == name {
  175.         if lp, err := LookPath(name); err != nil {
  176.             cmd.lookPathErr = err
  177.         } else {
  178.             cmd.Path = lp
  179.         }
  180.     }
  181.     return cmd
  182. }
  183.  
  184. // CommandContext is like Command but includes a context.
  185. //
  186. // The provided context is used to kill the process (by calling
  187. // os.Process.Kill) if the context becomes done before the command
  188. // completes on its own.
  189. func CommandContext(ctx context.Context, name string, arg ...string) *Cmd {
  190.     if ctx == nil {
  191.         panic("nil Context")
  192.     }
  193.     cmd := Command(name, arg...)
  194.     cmd.ctx = ctx
  195.     return cmd
  196. }
  197.  
  198. // String returns a human-readable description of c.
  199. // It is intended only for debugging.
  200. // In particular, it is not suitable for use as input to a shell.
  201. // The output of String may vary across Go releases.
  202. func (c *Cmd) String() string {
  203.     if c.lookPathErr != nil {
  204.         // failed to resolve path; report the original requested path (plus args)
  205.         return strings.Join(c.Args, " ")
  206.     }
  207.     // report the exact executable path (plus args)
  208.     b := new(strings.Builder)
  209.     b.WriteString(c.Path)
  210.     for _, a := range c.Args[1:] {
  211.         b.WriteByte(' ')
  212.         b.WriteString(a)
  213.     }
  214.     return b.String()
  215. }
  216.  
  217. // interfaceEqual protects against panics from doing equality tests on
  218. // two interfaces with non-comparable underlying types.
  219. func interfaceEqual(a, b interface{}) bool {
  220.     defer func() {
  221.         recover()
  222.     }()
  223.     return a == b
  224. }
  225.  
  226. func (c *Cmd) envv() ([]string, error) {
  227.     if c.Env != nil {
  228.         return c.Env, nil
  229.     }
  230.     return execenv.Default(c.SysProcAttr)
  231. }
  232.  
  233. func (c *Cmd) argv() []string {
  234.     if len(c.Args) > 0 {
  235.         return c.Args
  236.     }
  237.     return []string{c.Path}
  238. }
  239.  
  240. // skipStdinCopyError optionally specifies a function which reports
  241. // whether the provided stdin copy error should be ignored.
  242. var skipStdinCopyError func(error) bool
  243.  
  244. func (c *Cmd) stdin() (f *os.File, err error) {
  245.     if c.Stdin == nil {
  246.         f, err = os.Open(os.DevNull)
  247.         if err != nil {
  248.             return
  249.         }
  250.         c.closeAfterStart = append(c.closeAfterStart, f)
  251.         return
  252.     }
  253.  
  254.     if f, ok := c.Stdin.(*os.File); ok {
  255.         return f, nil
  256.     }
  257.  
  258.     pr, pw, err := os.Pipe()
  259.     if err != nil {
  260.         return
  261.     }
  262.  
  263.     c.closeAfterStart = append(c.closeAfterStart, pr)
  264.     c.closeAfterWait = append(c.closeAfterWait, pw)
  265.     c.goroutine = append(c.goroutine, func() error {
  266.         _, err := io.Copy(pw, c.Stdin)
  267.         if skip := skipStdinCopyError; skip != nil && skip(err) {
  268.             err = nil
  269.         }
  270.         if err1 := pw.Close(); err == nil {
  271.             err = err1
  272.         }
  273.         return err
  274.     })
  275.     return pr, nil
  276. }
  277.  
  278. func (c *Cmd) stdout() (f *os.File, err error) {
  279.     return c.writerDescriptor(c.Stdout)
  280. }
  281.  
  282. func (c *Cmd) stderr() (f *os.File, err error) {
  283.     if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
  284.         return c.childFiles[1], nil
  285.     }
  286.     return c.writerDescriptor(c.Stderr)
  287. }
  288.  
  289. func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
  290.     if w == nil {
  291.         f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
  292.         if err != nil {
  293.             return
  294.         }
  295.         c.closeAfterStart = append(c.closeAfterStart, f)
  296.         return
  297.     }
  298.  
  299.     if f, ok := w.(*os.File); ok {
  300.         return f, nil
  301.     }
  302.  
  303.     pr, pw, err := os.Pipe()
  304.     if err != nil {
  305.         return
  306.     }
  307.  
  308.     c.closeAfterStart = append(c.closeAfterStart, pw)
  309.     c.closeAfterWait = append(c.closeAfterWait, pr)
  310.     c.goroutine = append(c.goroutine, func() error {
  311.         _, err := io.Copy(w, pr)
  312.         pr.Close() // in case io.Copy stopped due to write error
  313.         return err
  314.     })
  315.     return pw, nil
  316. }
  317.  
  318. func (c *Cmd) closeDescriptors(closers []io.Closer) {
  319.     for _, fd := range closers {
  320.         fd.Close()
  321.     }
  322. }
  323.  
  324. // Run starts the specified command and waits for it to complete.
  325. //
  326. // The returned error is nil if the command runs, has no problems
  327. // copying stdin, stdout, and stderr, and exits with a zero exit
  328. // status.
  329. //
  330. // If the command starts but does not complete successfully, the error is of
  331. // type *ExitError. Other error types may be returned for other situations.
  332. //
  333. // If the calling goroutine has locked the operating system thread
  334. // with runtime.LockOSThread and modified any inheritable OS-level
  335. // thread state (for example, Linux or Plan 9 name spaces), the new
  336. // process will inherit the caller's thread state.
  337. func (c *Cmd) Run() error {
  338.     if err := c.Start(); err != nil {
  339.         return err
  340.     }
  341.     return c.Wait()
  342. }
  343.  
  344. // lookExtensions finds windows executable by its dir and path.
  345. // It uses LookPath to try appropriate extensions.
  346. // lookExtensions does not search PATH, instead it converts `prog` into `.\prog`.
  347. func lookExtensions(path, dir string) (string, error) {
  348.     if filepath.Base(path) == path {
  349.         path = filepath.Join(".", path)
  350.     }
  351.     if dir == "" {
  352.         return LookPath(path)
  353.     }
  354.     if filepath.VolumeName(path) != "" {
  355.         return LookPath(path)
  356.     }
  357.     if len(path) > 1 && os.IsPathSeparator(path[0]) {
  358.         return LookPath(path)
  359.     }
  360.     dirandpath := filepath.Join(dir, path)
  361.     // We assume that LookPath will only add file extension.
  362.     lp, err := LookPath(dirandpath)
  363.     if err != nil {
  364.         return "", err
  365.     }
  366.     ext := strings.TrimPrefix(lp, dirandpath)
  367.     return path + ext, nil
  368. }
  369.  
  370. // Start starts the specified command but does not wait for it to complete.
  371. //
  372. // If Start returns successfully, the c.Process field will be set.
  373. //
  374. // The Wait method will return the exit code and release associated resources
  375. // once the command exits.
  376. func (c *Cmd) Start() error {
  377.     if c.lookPathErr != nil {
  378.         c.closeDescriptors(c.closeAfterStart)
  379.         c.closeDescriptors(c.closeAfterWait)
  380.         return c.lookPathErr
  381.     }
  382.     if runtime.GOOS == "windows" {
  383.         lp, err := lookExtensions(c.Path, c.Dir)
  384.         if err != nil {
  385.             c.closeDescriptors(c.closeAfterStart)
  386.             c.closeDescriptors(c.closeAfterWait)
  387.             return err
  388.         }
  389.         c.Path = lp
  390.     }
  391.     if c.Process != nil {
  392.         return errors.New("exec: already started")
  393.     }
  394.     if c.ctx != nil {
  395.         select {
  396.         case <-c.ctx.Done():
  397.             c.closeDescriptors(c.closeAfterStart)
  398.             c.closeDescriptors(c.closeAfterWait)
  399.             return c.ctx.Err()
  400.         default:
  401.         }
  402.     }
  403.  
  404.     c.childFiles = make([]*os.File, 0, 3+len(c.ExtraFiles))
  405.     type F func(*Cmd) (*os.File, error)
  406.     for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
  407.         fd, err := setupFd(c)
  408.         if err != nil {
  409.             c.closeDescriptors(c.closeAfterStart)
  410.             c.closeDescriptors(c.closeAfterWait)
  411.             return err
  412.         }
  413.         c.childFiles = append(c.childFiles, fd)
  414.     }
  415.     c.childFiles = append(c.childFiles, c.ExtraFiles...)
  416.  
  417.     envv, err := c.envv()
  418.     if err != nil {
  419.         return err
  420.     }
  421.  
  422.     c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
  423.         Dir:   c.Dir,
  424.         Files: c.childFiles,
  425.         Env:   addCriticalEnv(dedupEnv(envv)),
  426.         Sys:   c.SysProcAttr,
  427.     })
  428.     if err != nil {
  429.         c.closeDescriptors(c.closeAfterStart)
  430.         c.closeDescriptors(c.closeAfterWait)
  431.         return err
  432.     }
  433.  
  434.     c.closeDescriptors(c.closeAfterStart)
  435.  
  436.     // Don't allocate the channel unless there are goroutines to fire.
  437.     if len(c.goroutine) > 0 {
  438.         c.errch = make(chan error, len(c.goroutine))
  439.         for _, fn := range c.goroutine {
  440.             go func(fn func() error) {
  441.                 c.errch <- fn()
  442.             }(fn)
  443.         }
  444.     }
  445.  
  446.     if c.ctx != nil {
  447.         c.waitDone = make(chan struct{})
  448.         go func() {
  449.             select {
  450.             case <-c.ctx.Done():
  451.                 c.Process.Kill()
  452.             case <-c.waitDone:
  453.             }
  454.         }()
  455.     }
  456.  
  457.     return nil
  458. }
  459.  
  460. // An ExitError reports an unsuccessful exit by a command.
  461. type ExitError struct {
  462.     *os.ProcessState
  463.  
  464.     // Stderr holds a subset of the standard error output from the
  465.     // Cmd.Output method if standard error was not otherwise being
  466.     // collected.
  467.     //
  468.     // If the error output is long, Stderr may contain only a prefix
  469.     // and suffix of the output, with the middle replaced with
  470.     // text about the number of omitted bytes.
  471.     //
  472.     // Stderr is provided for debugging, for inclusion in error messages.
  473.     // Users with other needs should redirect Cmd.Stderr as needed.
  474.     Stderr []byte
  475. }
  476.  
  477. func (e *ExitError) Error() string {
  478.     return e.ProcessState.String()
  479. }
  480.  
  481. // Wait waits for the command to exit and waits for any copying to
  482. // stdin or copying from stdout or stderr to complete.
  483. //
  484. // The command must have been started by Start.
  485. //
  486. // The returned error is nil if the command runs, has no problems
  487. // copying stdin, stdout, and stderr, and exits with a zero exit
  488. // status.
  489. //
  490. // If the command fails to run or doesn't complete successfully, the
  491. // error is of type *ExitError. Other error types may be
  492. // returned for I/O problems.
  493. //
  494. // If any of c.Stdin, c.Stdout or c.Stderr are not an *os.File, Wait also waits
  495. // for the respective I/O loop copying to or from the process to complete.
  496. //
  497. // Wait releases any resources associated with the Cmd.
  498. func (c *Cmd) Wait() error {
  499.     if c.Process == nil {
  500.         return errors.New("exec: not started")
  501.     }
  502.     if c.finished {
  503.         return errors.New("exec: Wait was already called")
  504.     }
  505.     c.finished = true
  506.  
  507.     state, err := c.Process.Wait()
  508.     if c.waitDone != nil {
  509.         close(c.waitDone)
  510.     }
  511.     c.ProcessState = state
  512.  
  513.     var copyError error
  514.     for range c.goroutine {
  515.         if err := <-c.errch; err != nil && copyError == nil {
  516.             copyError = err
  517.         }
  518.     }
  519.  
  520.     c.closeDescriptors(c.closeAfterWait)
  521.  
  522.     if err != nil {
  523.         return err
  524.     } else if !state.Success() {
  525.         return &ExitError{ProcessState: state}
  526.     }
  527.  
  528.     return copyError
  529. }
  530.  
  531. // Output runs the command and returns its standard output.
  532. // Any returned error will usually be of type *ExitError.
  533. // If c.Stderr was nil, Output populates ExitError.Stderr.
  534. func (c *Cmd) Output() ([]byte, error) {
  535.     if c.Stdout != nil {
  536.         return nil, errors.New("exec: Stdout already set")
  537.     }
  538.     var stdout bytes.Buffer
  539.     c.Stdout = &stdout
  540.  
  541.     captureErr := c.Stderr == nil
  542.     if captureErr {
  543.         c.Stderr = &prefixSuffixSaver{N: 32 << 10}
  544.     }
  545.  
  546.     err := c.Run()
  547.     if err != nil && captureErr {
  548.         if ee, ok := err.(*ExitError); ok {
  549.             ee.Stderr = c.Stderr.(*prefixSuffixSaver).Bytes()
  550.         }
  551.     }
  552.     return stdout.Bytes(), err
  553. }
  554.  
  555. // CombinedOutput runs the command and returns its combined standard
  556. // output and standard error.
  557. func (c *Cmd) CombinedOutput() ([]byte, error) {
  558.     if c.Stdout != nil {
  559.         return nil, errors.New("exec: Stdout already set")
  560.     }
  561.     if c.Stderr != nil {
  562.         return nil, errors.New("exec: Stderr already set")
  563.     }
  564.     var b bytes.Buffer
  565.     c.Stdout = &b
  566.     c.Stderr = &b
  567.     err := c.Run()
  568.     return b.Bytes(), err
  569. }
  570.  
  571. // StdinPipe returns a pipe that will be connected to the command's
  572. // standard input when the command starts.
  573. // The pipe will be closed automatically after Wait sees the command exit.
  574. // A caller need only call Close to force the pipe to close sooner.
  575. // For example, if the command being run will not exit until standard input
  576. // is closed, the caller must close the pipe.
  577. func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
  578.     if c.Stdin != nil {
  579.         return nil, errors.New("exec: Stdin already set")
  580.     }
  581.     if c.Process != nil {
  582.         return nil, errors.New("exec: StdinPipe after process started")
  583.     }
  584.     pr, pw, err := os.Pipe()
  585.     if err != nil {
  586.         return nil, err
  587.     }
  588.     c.Stdin = pr
  589.     c.closeAfterStart = append(c.closeAfterStart, pr)
  590.     wc := &closeOnce{File: pw}
  591.     c.closeAfterWait = append(c.closeAfterWait, wc)
  592.     return wc, nil
  593. }
  594.  
  595. type closeOnce struct {
  596.     *os.File
  597.  
  598.     once sync.Once
  599.     err  error
  600. }
  601.  
  602. func (c *closeOnce) Close() error {
  603.     c.once.Do(c.close)
  604.     return c.err
  605. }
  606.  
  607. func (c *closeOnce) close() {
  608.     c.err = c.File.Close()
  609. }
  610.  
  611. // StdoutPipe returns a pipe that will be connected to the command's
  612. // standard output when the command starts.
  613. //
  614. // Wait will close the pipe after seeing the command exit, so most callers
  615. // need not close the pipe themselves. It is thus incorrect to call Wait
  616. // before all reads from the pipe have completed.
  617. // For the same reason, it is incorrect to call Run when using StdoutPipe.
  618. // See the example for idiomatic usage.
  619. func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
  620.     if c.Stdout != nil {
  621.         return nil, errors.New("exec: Stdout already set")
  622.     }
  623.     if c.Process != nil {
  624.         return nil, errors.New("exec: StdoutPipe after process started")
  625.     }
  626.     pr, pw, err := os.Pipe()
  627.     if err != nil {
  628.         return nil, err
  629.     }
  630.     c.Stdout = pw
  631.     c.closeAfterStart = append(c.closeAfterStart, pw)
  632.     c.closeAfterWait = append(c.closeAfterWait, pr)
  633.     return pr, nil
  634. }
  635.  
  636. // StderrPipe returns a pipe that will be connected to the command's
  637. // standard error when the command starts.
  638. //
  639. // Wait will close the pipe after seeing the command exit, so most callers
  640. // need not close the pipe themselves. It is thus incorrect to call Wait
  641. // before all reads from the pipe have completed.
  642. // For the same reason, it is incorrect to use Run when using StderrPipe.
  643. // See the StdoutPipe example for idiomatic usage.
  644. func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
  645.     if c.Stderr != nil {
  646.         return nil, errors.New("exec: Stderr already set")
  647.     }
  648.     if c.Process != nil {
  649.         return nil, errors.New("exec: StderrPipe after process started")
  650.     }
  651.     pr, pw, err := os.Pipe()
  652.     if err != nil {
  653.         return nil, err
  654.     }
  655.     c.Stderr = pw
  656.     c.closeAfterStart = append(c.closeAfterStart, pw)
  657.     c.closeAfterWait = append(c.closeAfterWait, pr)
  658.     return pr, nil
  659. }
  660.  
  661. // prefixSuffixSaver is an io.Writer which retains the first N bytes
  662. // and the last N bytes written to it. The Bytes() methods reconstructs
  663. // it with a pretty error message.
  664. type prefixSuffixSaver struct {
  665.     N         int // max size of prefix or suffix
  666.     prefix    []byte
  667.     suffix    []byte // ring buffer once len(suffix) == N
  668.     suffixOff int    // offset to write into suffix
  669.     skipped   int64
  670.  
  671.     // TODO(bradfitz): we could keep one large []byte and use part of it for
  672.     // the prefix, reserve space for the '... Omitting N bytes ...' message,
  673.     // then the ring buffer suffix, and just rearrange the ring buffer
  674.     // suffix when Bytes() is called, but it doesn't seem worth it for
  675.     // now just for error messages. It's only ~64KB anyway.
  676. }
  677.  
  678. func (w *prefixSuffixSaver) Write(p []byte) (n int, err error) {
  679.     lenp := len(p)
  680.     p = w.fill(&w.prefix, p)
  681.  
  682.     // Only keep the last w.N bytes of suffix data.
  683.     if overage := len(p) - w.N; overage > 0 {
  684.         p = p[overage:]
  685.         w.skipped += int64(overage)
  686.     }
  687.     p = w.fill(&w.suffix, p)
  688.  
  689.     // w.suffix is full now if p is non-empty. Overwrite it in a circle.
  690.     for len(p) > 0 { // 0, 1, or 2 iterations.
  691.         n := copy(w.suffix[w.suffixOff:], p)
  692.         p = p[n:]
  693.         w.skipped += int64(n)
  694.         w.suffixOff += n
  695.         if w.suffixOff == w.N {
  696.             w.suffixOff = 0
  697.         }
  698.     }
  699.     return lenp, nil
  700. }
  701.  
  702. // fill appends up to len(p) bytes of p to *dst, such that *dst does not
  703. // grow larger than w.N. It returns the un-appended suffix of p.
  704. func (w *prefixSuffixSaver) fill(dst *[]byte, p []byte) (pRemain []byte) {
  705.     if remain := w.N - len(*dst); remain > 0 {
  706.         add := minInt(len(p), remain)
  707.         *dst = append(*dst, p[:add]...)
  708.         p = p[add:]
  709.     }
  710.     return p
  711. }
  712.  
  713. func (w *prefixSuffixSaver) Bytes() []byte {
  714.     if w.suffix == nil {
  715.         return w.prefix
  716.     }
  717.     if w.skipped == 0 {
  718.         return append(w.prefix, w.suffix...)
  719.     }
  720.     var buf bytes.Buffer
  721.     buf.Grow(len(w.prefix) + len(w.suffix) + 50)
  722.     buf.Write(w.prefix)
  723.     buf.WriteString("\n... omitting ")
  724.     buf.WriteString(strconv.FormatInt(w.skipped, 10))
  725.     buf.WriteString(" bytes ...\n")
  726.     buf.Write(w.suffix[w.suffixOff:])
  727.     buf.Write(w.suffix[:w.suffixOff])
  728.     return buf.Bytes()
  729. }
  730.  
  731. func minInt(a, b int) int {
  732.     if a < b {
  733.         return a
  734.     }
  735.     return b
  736. }
  737.  
  738. // dedupEnv returns a copy of env with any duplicates removed, in favor of
  739. // later values.
  740. // Items not of the normal environment "key=value" form are preserved unchanged.
  741. func dedupEnv(env []string) []string {
  742.     return dedupEnvCase(runtime.GOOS == "windows", env)
  743. }
  744.  
  745. // dedupEnvCase is dedupEnv with a case option for testing.
  746. // If caseInsensitive is true, the case of keys is ignored.
  747. func dedupEnvCase(caseInsensitive bool, env []string) []string {
  748.     out := make([]string, 0, len(env))
  749.     saw := make(map[string]int, len(env)) // key => index into out
  750.     for _, kv := range env {
  751.         eq := strings.Index(kv, "=")
  752.         if eq < 0 {
  753.             out = append(out, kv)
  754.             continue
  755.         }
  756.         k := kv[:eq]
  757.         if caseInsensitive {
  758.             k = strings.ToLower(k)
  759.         }
  760.         if dupIdx, isDup := saw[k]; isDup {
  761.             out[dupIdx] = kv
  762.             continue
  763.         }
  764.         saw[k] = len(out)
  765.         out = append(out, kv)
  766.     }
  767.     return out
  768. }
  769.  
  770. // addCriticalEnv adds any critical environment variables that are required
  771. // (or at least almost always required) on the operating system.
  772. // Currently this is only used for Windows.
  773. func addCriticalEnv(env []string) []string {
  774.     if runtime.GOOS != "windows" {
  775.         return env
  776.     }
  777.     for _, kv := range env {
  778.         eq := strings.Index(kv, "=")
  779.         if eq < 0 {
  780.             continue
  781.         }
  782.         k := kv[:eq]
  783.         if strings.EqualFold(k, "SYSTEMROOT") {
  784.             // We already have it.
  785.             return env
  786.         }
  787.     }
  788.     return append(env, "SYSTEMROOT="+os.Getenv("SYSTEMROOT"))
  789. }
  790.  
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×