// Copyright 2022 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build ignore // +build ignore // The copyfiles script copies the contents of the internal cmd/go robustio // package to the current directory, with adjustments to make it build. // // NOTE: In retrospect this script got out of hand, as we have to perform // various operations on the package to get it to build at old Go versions. If // in the future it proves to be flaky, delete it and just copy code manually. package main import ( "bytes" "go/build/constraint" "go/scanner" "go/token" "log" "os" "path/filepath" "runtime" "strings" ) func main() { dir := filepath.Join(runtime.GOROOT(), "src", "cmd", "go", "internal", "robustio") entries, err := os.ReadDir(dir) if err != nil { log.Fatalf("reading the robustio dir: %v", err) } // Collect file content so that we can validate before copying. fileContent := make(map[string][]byte) windowsImport := []byte("\t\"internal/syscall/windows\"\n") foundWindowsImport := false for _, entry := range entries { if strings.HasSuffix(entry.Name(), ".go") { pth := filepath.Join(dir, entry.Name()) content, err := os.ReadFile(pth) if err != nil { log.Fatalf("reading %q: %v", entry.Name(), err) } // Replace the use of internal/syscall/windows.ERROR_SHARING_VIOLATION // with a local constant. if entry.Name() == "robustio_windows.go" && bytes.Contains(content, windowsImport) { foundWindowsImport = true content = bytes.Replace(content, windowsImport, nil, 1) content = bytes.Replace(content, []byte("windows.ERROR_SHARING_VIOLATION"), []byte("ERROR_SHARING_VIOLATION"), -1) } // Replace os.ReadFile with os.ReadFile (for 1.15 and older). We // attempt to match calls (via the '('), to avoid matching mentions of // os.ReadFile in comments. // // TODO(rfindley): once we (shortly!) no longer support 1.15, remove // this and break the build. if bytes.Contains(content, []byte("os.ReadFile(")) { content = bytes.Replace(content, []byte("\"os\""), []byte("\"io/ioutil\"\n\t\"os\""), 1) content = bytes.Replace(content, []byte("os.ReadFile("), []byte("os.ReadFile("), -1) } // Add +build constraints, for 1.16. content = addPlusBuildConstraints(content) fileContent[entry.Name()] = content } } if !foundWindowsImport { log.Fatal("missing expected import of internal/syscall/windows in robustio_windows.go") } for name, content := range fileContent { if err := os.WriteFile(name, content, 0644); err != nil { log.Fatalf("writing %q: %v", name, err) } } } // addPlusBuildConstraints splices in +build constraints for go:build // constraints encountered in the source. // // Gopls still builds at Go 1.16, which requires +build constraints. func addPlusBuildConstraints(src []byte) []byte { var s scanner.Scanner fset := token.NewFileSet() file := fset.AddFile("", fset.Base(), len(src)) s.Init(file, src, nil /* no error handler */, scanner.ScanComments) result := make([]byte, 0, len(src)) lastInsertion := 0 for { pos, tok, lit := s.Scan() if tok == token.EOF { break } if tok == token.COMMENT { if c, err := constraint.Parse(lit); err == nil { plusBuild, err := constraint.PlusBuildLines(c) if err != nil { log.Fatalf("computing +build constraint for %q: %v", lit, err) } insertAt := file.Offset(pos) + len(lit) result = append(result, src[lastInsertion:insertAt]...) result = append(result, []byte("\n"+strings.Join(plusBuild, "\n"))...) lastInsertion = insertAt } } } result = append(result, src[lastInsertion:]...) return result }