github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/add-check.go (about)

     1  //go:build ignore
     2  
     3  package main
     4  
     5  import (
     6  	"bytes"
     7  	"go/format"
     8  	"log"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"regexp"
    13  	"strings"
    14  	"text/template"
    15  )
    16  
    17  var tmpl = `
    18  package {{.lname}}
    19  
    20  import (
    21  	"github.com/amarpal/go-tools/analysis/lint"
    22  
    23  	"golang.org/x/tools/go/analysis"
    24  )
    25  
    26  var SCAnalyzer = lint.InitializeAnalyzer(&lint.Analyzer{
    27  	Analyzer: &analysis.Analyzer{
    28  		Name: "{{.name}}",
    29  		Run: run,
    30  		Requires: []*analysis.Analyzer{},
    31  	},
    32  	Doc: &lint.Documentation{
    33  		Title: "",
    34  		Text: {{.emptyRaw}},
    35  		{{- if .quickfix }}
    36  		Before: {{.emptyRaw}},
    37  		After: {{.emptyRaw}},
    38  		{{- end }}
    39  		Since: "Unreleased",
    40  		Severity: lint.SeverityWarning,
    41  	},
    42  })
    43  
    44  var Analyzer = SCAnalyzer.Analyzer
    45  
    46  func run(pass *analysis.Pass) (interface{}, error) {
    47  	return nil, nil
    48  }
    49  `
    50  
    51  func main() {
    52  	log.SetFlags(0)
    53  
    54  	var t template.Template
    55  	if _, err := t.Parse(tmpl); err != nil {
    56  		log.Fatalln("couldn't parse template:", err)
    57  	}
    58  
    59  	if len(os.Args) != 2 {
    60  		log.Fatalf("Usage: %s <new check's name>", os.Args[0])
    61  	}
    62  
    63  	name := os.Args[1]
    64  	checkRe := regexp.MustCompile(`^([A-Za-z]+)\d{4}$`)
    65  	parts := checkRe.FindStringSubmatch(name)
    66  	if parts == nil {
    67  		log.Fatalf("invalid check name %q", name)
    68  	}
    69  
    70  	var catDir string
    71  	prefix := strings.ToUpper(parts[1])
    72  	switch prefix {
    73  	case "SA":
    74  		catDir = "staticcheck"
    75  	case "S":
    76  		catDir = "simple"
    77  	case "ST":
    78  		catDir = "stylecheck"
    79  	case "QF":
    80  		catDir = "quickfix"
    81  	default:
    82  		log.Fatalf("unknown check prefix %q", prefix)
    83  	}
    84  
    85  	lname := strings.ToLower(name)
    86  	dir := filepath.Join(catDir, lname)
    87  	dst := filepath.Join(dir, lname+".go")
    88  
    89  	mkdirp(dir)
    90  
    91  	buf := bytes.NewBuffer(nil)
    92  	vars := map[string]any{
    93  		"name":     name,
    94  		"lname":    lname,
    95  		"emptyRaw": "``",
    96  		"quickfix": prefix == "QF",
    97  	}
    98  
    99  	if err := t.Execute(buf, vars); err != nil {
   100  		log.Fatalf("couldn't generate %s: %s", dst, err)
   101  	}
   102  
   103  	b, err := format.Source(buf.Bytes())
   104  	if err != nil {
   105  		log.Fatalf("couldn't gofmt %s: %s", dst, err)
   106  	}
   107  
   108  	writeFile(dst, b)
   109  
   110  	testdata := filepath.Join(dir, "testdata", "src", "example.com", "pkg")
   111  	mkdirp(testdata)
   112  	writeFile(filepath.Join(testdata, "pkg.go"), []byte("package pkg\n"))
   113  
   114  	out, err := exec.Command("go", "generate", "./...").CombinedOutput()
   115  	if err != nil {
   116  		log.Printf("could not run 'go generate ./...': %s", err)
   117  		log.Println("Output:")
   118  		log.Fatalln(string(out))
   119  	}
   120  
   121  	flags := []string{
   122  		"add",
   123  		"--intent-to-add",
   124  		"--verbose",
   125  
   126  		filepath.Join(dir, lname+"_test.go"),
   127  		filepath.Join(testdata, "pkg.go"),
   128  		dst,
   129  	}
   130  	cmd := exec.Command("git", flags...)
   131  	cmd.Stdout = os.Stdout
   132  	cmd.Stderr = os.Stderr
   133  	if err := cmd.Run(); err != nil {
   134  		log.Fatalln("could not run 'git add':", err)
   135  	}
   136  }
   137  
   138  func writeFile(path string, data []byte) {
   139  	if err := os.WriteFile(path, data, 0677); err != nil {
   140  		log.Fatalf("couldn't write %s: %s", path, err)
   141  	}
   142  }
   143  
   144  func mkdirp(path string) {
   145  	if err := os.MkdirAll(path, 0777); err != nil {
   146  		log.Fatalf("couldn't create directory %s: %s", path, err)
   147  	}
   148  }