src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

scan.go (2846B)


      1 // Copyright 2023 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 /*
      6 Package scan provides functionality for running govulncheck.
      7 
      8 See [cmd/govulncheck/main.go] as a usage example.
      9 
     10 [cmd/govulncheck/main.go]: https://go.googlesource.com/vuln/+/master/cmd/govulncheck/main.go
     11 */
     12 package scan
     13 
     14 import (
     15 	"context"
     16 	"errors"
     17 	"io"
     18 	"os"
     19 
     20 	"golang.org/x/vuln/internal/scan"
     21 )
     22 
     23 // Cmd represents an external govulncheck command being prepared or run,
     24 // similar to exec.Cmd.
     25 type Cmd struct {
     26 	// Stdin specifies the standard input. If provided, it is expected to be
     27 	// the output of govulncheck -json.
     28 	Stdin io.Reader
     29 
     30 	// Stdout specifies the standard output. If nil, Run connects os.Stdout.
     31 	Stdout io.Writer
     32 
     33 	// Stderr specifies the standard error. If nil, Run connects os.Stderr.
     34 	Stderr io.Writer
     35 
     36 	// Env is the environment to use.
     37 	// If Env is nil, the current environment is used.
     38 	// As in os/exec's Cmd, only the last value in the slice for
     39 	// each environment key is used. To specify the setting of only
     40 	// a few variables, append to the current environment, as in:
     41 	//
     42 	//	opt.Env = append(os.Environ(), "GOOS=plan9", "GOARCH=386")
     43 	//
     44 	Env []string
     45 
     46 	ctx  context.Context
     47 	args []string
     48 	done chan struct{}
     49 	err  error
     50 }
     51 
     52 // Command returns the Cmd struct to execute govulncheck with the given
     53 // arguments.
     54 func Command(ctx context.Context, arg ...string) *Cmd {
     55 	return &Cmd{
     56 		ctx:  ctx,
     57 		args: arg,
     58 	}
     59 }
     60 
     61 // Start starts the specified command but does not wait for it to complete.
     62 //
     63 // After a successful call to Start the Wait method must be called in order to
     64 // release associated system resources.
     65 func (c *Cmd) Start() error {
     66 	if c.done != nil {
     67 		return errors.New("vuln: already started")
     68 	}
     69 	if c.Stdin == nil {
     70 		c.Stdin = os.Stdin
     71 	}
     72 	if c.Stdout == nil {
     73 		c.Stdout = os.Stdout
     74 	}
     75 	if c.Stderr == nil {
     76 		c.Stderr = os.Stderr
     77 	}
     78 	if c.Env == nil {
     79 		c.Env = os.Environ()
     80 	}
     81 	c.done = make(chan struct{})
     82 	go func() {
     83 		defer close(c.done)
     84 		c.err = c.scan()
     85 	}()
     86 	return nil
     87 }
     88 
     89 // Wait waits for the command to exit. The command must have been started by
     90 // Start.
     91 //
     92 // If the command fails to run or does not complete successfully, the returned
     93 // error wraps an error implementing:
     94 //
     95 //	interface {
     96 //		ExitCode() int
     97 //	}
     98 //
     99 // Callers can use errors.As to retrieve the exit code. Other errors may be
    100 // returned for other problems (e.g. I/O issues).
    101 //
    102 // Wait releases any resources associated with the Cmd.
    103 func (c *Cmd) Wait() error {
    104 	if c.done == nil {
    105 		return errors.New("vuln: start must be called before wait")
    106 	}
    107 	<-c.done
    108 	return c.err
    109 }
    110 
    111 func (c *Cmd) scan() error {
    112 	if err := c.ctx.Err(); err != nil {
    113 		return err
    114 	}
    115 	return scan.RunGovulncheck(c.ctx, c.Env, c.Stdin, c.Stdout, c.Stderr, c.args)
    116 }