golang.org/x/playground@v0.0.0-20230418134305-14ebe15bcd59/vet.go (about)

     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
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"os"
    11  	"os/exec"
    12  	"path/filepath"
    13  	"strings"
    14  	"time"
    15  
    16  	"go.opencensus.io/stats"
    17  	"go.opencensus.io/tag"
    18  )
    19  
    20  // vetCheck runs the "vet" tool on the source code in req.Body.
    21  // In case of no errors it returns an empty, non-nil *response.
    22  // Otherwise &response.Errors contains found errors.
    23  //
    24  // Deprecated: this is the handler for the legacy /vet endpoint; use
    25  // the /compile (compileAndRun) handler instead with the WithVet
    26  // boolean set. This code path doesn't support modules and only exists
    27  // as a temporary compatibility bridge to older javascript clients.
    28  func vetCheck(ctx context.Context, req *request) (*response, error) {
    29  	tmpDir, err := os.MkdirTemp("", "vet")
    30  	if err != nil {
    31  		return nil, fmt.Errorf("error creating temp directory: %v", err)
    32  	}
    33  	defer os.RemoveAll(tmpDir)
    34  
    35  	in := filepath.Join(tmpDir, progName)
    36  	if err := os.WriteFile(in, []byte(req.Body), 0400); err != nil {
    37  		return nil, fmt.Errorf("error creating temp file %q: %v", in, err)
    38  	}
    39  	vetOutput, err := vetCheckInDir(ctx, tmpDir, os.Getenv("GOPATH"))
    40  	if err != nil {
    41  		// This is about errors running vet, not vet returning output.
    42  		return nil, err
    43  	}
    44  	return &response{Errors: vetOutput}, nil
    45  }
    46  
    47  // vetCheckInDir runs go vet in the provided directory, using the
    48  // provided GOPATH value. The returned error is only about whether
    49  // go vet was able to run, not whether vet reported problem. The
    50  // returned value is ("", nil) if vet successfully found nothing,
    51  // and (non-empty, nil) if vet ran and found issues.
    52  func vetCheckInDir(ctx context.Context, dir, goPath string) (output string, execErr error) {
    53  	start := time.Now()
    54  	defer func() {
    55  		status := "success"
    56  		if execErr != nil {
    57  			status = "error"
    58  		}
    59  		// Ignore error. The only error can be invalid tag key or value
    60  		// length, which we know are safe.
    61  		stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(kGoVetSuccess, status)},
    62  			mGoVetLatency.M(float64(time.Since(start))/float64(time.Millisecond)))
    63  	}()
    64  
    65  	cmd := exec.Command("go", "vet", "--tags=faketime", "--mod=mod")
    66  	cmd.Dir = dir
    67  	// Linux go binary is not built with CGO_ENABLED=0.
    68  	// Prevent vet to compile packages in cgo mode.
    69  	// See #26307.
    70  	cmd.Env = append(os.Environ(), "CGO_ENABLED=0", "GOPATH="+goPath)
    71  	cmd.Env = append(cmd.Env,
    72  		"GO111MODULE=on",
    73  		"GOPROXY="+playgroundGoproxy(),
    74  	)
    75  	out, err := cmd.CombinedOutput()
    76  	if err == nil {
    77  		return "", nil
    78  	}
    79  	if _, ok := err.(*exec.ExitError); !ok {
    80  		return "", fmt.Errorf("error vetting go source: %v", err)
    81  	}
    82  
    83  	// Rewrite compiler errors to refer to progName
    84  	// instead of '/tmp/sandbox1234/main.go'.
    85  	errs := strings.Replace(string(out), dir, "", -1)
    86  	errs = removeBanner(errs)
    87  	return errs, nil
    88  }