golang.org/x/tools/gopls@v0.15.3/internal/vulncheck/copier.go (about) 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 //go:build ignore 6 // +build ignore 7 8 //go:generate go run ./copier.go 9 10 // Copier is a tool to automate copy of govulncheck's internal files. 11 // 12 // - copy golang.org/x/vuln/internal/osv/ to osv 13 // - copy golang.org/x/vuln/internal/govulncheck/ to govulncheck 14 package main 15 16 import ( 17 "bytes" 18 "encoding/json" 19 "fmt" 20 "go/parser" 21 "go/token" 22 "log" 23 "os" 24 "os/exec" 25 "path/filepath" 26 "strconv" 27 "strings" 28 29 "golang.org/x/tools/internal/edit" 30 ) 31 32 func main() { 33 log.SetPrefix("copier: ") 34 log.SetFlags(log.Lshortfile) 35 36 srcMod := "golang.org/x/vuln" 37 srcModVers := "@latest" 38 srcDir, srcVer := downloadModule(srcMod + srcModVers) 39 40 cfg := rewrite{ 41 banner: fmt.Sprintf("// Code generated by copying from %v@%v (go run copier.go); DO NOT EDIT.", srcMod, srcVer), 42 srcImportPath: "golang.org/x/vuln/internal", 43 dstImportPath: currentPackagePath(), 44 } 45 46 copyFiles("osv", filepath.Join(srcDir, "internal", "osv"), cfg) 47 copyFiles("govulncheck", filepath.Join(srcDir, "internal", "govulncheck"), cfg) 48 } 49 50 type rewrite struct { 51 // DO NOT EDIT marker to add at the beginning 52 banner string 53 // rewrite srcImportPath with dstImportPath 54 srcImportPath string 55 dstImportPath string 56 } 57 58 func copyFiles(dst, src string, cfg rewrite) { 59 entries, err := os.ReadDir(src) 60 if err != nil { 61 log.Fatalf("failed to read dir: %v", err) 62 } 63 if err := os.MkdirAll(dst, 0777); err != nil { 64 log.Fatalf("failed to create dir: %v", err) 65 } 66 67 for _, e := range entries { 68 fname := e.Name() 69 // we need only non-test go files. 70 if e.IsDir() || !strings.HasSuffix(fname, ".go") || strings.HasSuffix(fname, "_test.go") { 71 continue 72 } 73 data, err := os.ReadFile(filepath.Join(src, fname)) 74 if err != nil { 75 log.Fatal(err) 76 } 77 fset := token.NewFileSet() 78 f, err := parser.ParseFile(fset, fname, data, parser.ParseComments|parser.ImportsOnly) 79 if err != nil { 80 log.Fatalf("parsing source module:\n%s", err) 81 } 82 83 buf := edit.NewBuffer(data) 84 at := func(p token.Pos) int { 85 return fset.File(p).Offset(p) 86 } 87 88 // Add banner right after the copyright statement (the first comment) 89 bannerInsert, banner := f.FileStart, cfg.banner 90 if len(f.Comments) > 0 && strings.HasPrefix(f.Comments[0].Text(), "Copyright ") { 91 bannerInsert = f.Comments[0].End() 92 banner = "\n\n" + banner 93 } 94 buf.Replace(at(bannerInsert), at(bannerInsert), banner) 95 96 // Adjust imports 97 for _, spec := range f.Imports { 98 path, err := strconv.Unquote(spec.Path.Value) 99 if err != nil { 100 log.Fatal(err) 101 } 102 if strings.HasPrefix(path, cfg.srcImportPath) { 103 newPath := strings.Replace(path, cfg.srcImportPath, cfg.dstImportPath, 1) 104 buf.Replace(at(spec.Path.Pos()), at(spec.Path.End()), strconv.Quote(newPath)) 105 } 106 } 107 data = buf.Bytes() 108 109 if err := os.WriteFile(filepath.Join(dst, fname), data, 0666); err != nil { 110 log.Fatal(err) 111 } 112 } 113 } 114 115 func downloadModule(srcModVers string) (dir, ver string) { 116 var stdout, stderr bytes.Buffer 117 cmd := exec.Command("go", "mod", "download", "-json", srcModVers) 118 cmd.Stdout = &stdout 119 cmd.Stderr = &stderr 120 if err := cmd.Run(); err != nil { 121 log.Fatalf("go mod download -json %s: %v\n%s%s", srcModVers, err, stderr.Bytes(), stdout.Bytes()) 122 } 123 var info struct { 124 Dir string 125 Version string 126 } 127 if err := json.Unmarshal(stdout.Bytes(), &info); err != nil { 128 log.Fatalf("go mod download -json %s: invalid JSON output: %v\n%s%s", srcModVers, err, stderr.Bytes(), stdout.Bytes()) 129 } 130 return info.Dir, info.Version 131 } 132 133 func currentPackagePath() string { 134 var stdout, stderr bytes.Buffer 135 cmd := exec.Command("go", "list", ".") 136 cmd.Stdout = &stdout 137 cmd.Stderr = &stderr 138 if err := cmd.Run(); err != nil { 139 log.Fatalf("go list: %v\n%s%s", err, stderr.Bytes(), stdout.Bytes()) 140 } 141 return strings.TrimSpace(stdout.String()) 142 }