golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/internal/robustio/copyfiles.go (about) 1 // Copyright 2022 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 // The copyfiles script copies the contents of the internal cmd/go robustio 9 // package to the current directory, with adjustments to make it build. 10 // 11 // NOTE: In retrospect this script got out of hand, as we have to perform 12 // various operations on the package to get it to build at old Go versions. If 13 // in the future it proves to be flaky, delete it and just copy code manually. 14 package main 15 16 import ( 17 "bytes" 18 "go/build/constraint" 19 "go/scanner" 20 "go/token" 21 "log" 22 "os" 23 "path/filepath" 24 "runtime" 25 "strings" 26 ) 27 28 func main() { 29 dir := filepath.Join(runtime.GOROOT(), "src", "cmd", "go", "internal", "robustio") 30 31 entries, err := os.ReadDir(dir) 32 if err != nil { 33 log.Fatalf("reading the robustio dir: %v", err) 34 } 35 36 // Collect file content so that we can validate before copying. 37 fileContent := make(map[string][]byte) 38 windowsImport := []byte("\t\"internal/syscall/windows\"\n") 39 foundWindowsImport := false 40 for _, entry := range entries { 41 if strings.HasSuffix(entry.Name(), ".go") { 42 pth := filepath.Join(dir, entry.Name()) 43 content, err := os.ReadFile(pth) 44 if err != nil { 45 log.Fatalf("reading %q: %v", entry.Name(), err) 46 } 47 48 // Replace the use of internal/syscall/windows.ERROR_SHARING_VIOLATION 49 // with a local constant. 50 if entry.Name() == "robustio_windows.go" && bytes.Contains(content, windowsImport) { 51 foundWindowsImport = true 52 content = bytes.Replace(content, windowsImport, nil, 1) 53 content = bytes.Replace(content, []byte("windows.ERROR_SHARING_VIOLATION"), []byte("ERROR_SHARING_VIOLATION"), -1) 54 } 55 56 // Replace os.ReadFile with os.ReadFile (for 1.15 and older). We 57 // attempt to match calls (via the '('), to avoid matching mentions of 58 // os.ReadFile in comments. 59 // 60 // TODO(rfindley): once we (shortly!) no longer support 1.15, remove 61 // this and break the build. 62 if bytes.Contains(content, []byte("os.ReadFile(")) { 63 content = bytes.Replace(content, []byte("\"os\""), []byte("\"io/ioutil\"\n\t\"os\""), 1) 64 content = bytes.Replace(content, []byte("os.ReadFile("), []byte("os.ReadFile("), -1) 65 } 66 67 // Add +build constraints, for 1.16. 68 content = addPlusBuildConstraints(content) 69 70 fileContent[entry.Name()] = content 71 } 72 } 73 74 if !foundWindowsImport { 75 log.Fatal("missing expected import of internal/syscall/windows in robustio_windows.go") 76 } 77 78 for name, content := range fileContent { 79 if err := os.WriteFile(name, content, 0644); err != nil { 80 log.Fatalf("writing %q: %v", name, err) 81 } 82 } 83 } 84 85 // addPlusBuildConstraints splices in +build constraints for go:build 86 // constraints encountered in the source. 87 // 88 // Gopls still builds at Go 1.16, which requires +build constraints. 89 func addPlusBuildConstraints(src []byte) []byte { 90 var s scanner.Scanner 91 fset := token.NewFileSet() 92 file := fset.AddFile("", fset.Base(), len(src)) 93 s.Init(file, src, nil /* no error handler */, scanner.ScanComments) 94 95 result := make([]byte, 0, len(src)) 96 lastInsertion := 0 97 for { 98 pos, tok, lit := s.Scan() 99 if tok == token.EOF { 100 break 101 } 102 if tok == token.COMMENT { 103 if c, err := constraint.Parse(lit); err == nil { 104 plusBuild, err := constraint.PlusBuildLines(c) 105 if err != nil { 106 log.Fatalf("computing +build constraint for %q: %v", lit, err) 107 } 108 insertAt := file.Offset(pos) + len(lit) 109 result = append(result, src[lastInsertion:insertAt]...) 110 result = append(result, []byte("\n"+strings.Join(plusBuild, "\n"))...) 111 lastInsertion = insertAt 112 } 113 } 114 } 115 result = append(result, src[lastInsertion:]...) 116 return result 117 }