1// run
2
3// Copyright 2020 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7// Check that batch files are maintained as CRLF files (consistent
8// behavior on all operating systems). See golang.org/issue/37791.
9
10package main
11
12import (
13	"bytes"
14	"fmt"
15	"io/ioutil"
16	"log"
17	"os"
18	"path/filepath"
19	"runtime"
20	"strings"
21)
22
23func main() {
24	// Ensure that the GOROOT/src/all.bat file exists and has strict CRLF line endings.
25	enforceBatchStrictCRLF(filepath.Join(runtime.GOROOT(), "src", "all.bat"))
26
27	// Walk the entire Go repository source tree (without GOROOT/pkg),
28	// skipping directories that start with "." and named "testdata",
29	// and ensure all .bat files found have exact CRLF line endings.
30	err := filepath.WalkDir(runtime.GOROOT(), func(path string, d os.DirEntry, err error) error {
31		if err != nil {
32			return err
33		}
34		if d.IsDir() && (strings.HasPrefix(d.Name(), ".") || d.Name() == "testdata") {
35			return filepath.SkipDir
36		}
37		if path == filepath.Join(runtime.GOROOT(), "pkg") {
38			// GOROOT/pkg is known to contain generated artifacts, not source code.
39			// Skip it to avoid false positives. (Also see golang.org/issue/37929.)
40			return filepath.SkipDir
41		}
42		if filepath.Ext(d.Name()) == ".bat" {
43			enforceBatchStrictCRLF(path)
44		}
45		return nil
46	})
47	if err != nil {
48		log.Fatalln(err)
49	}
50}
51
52func enforceBatchStrictCRLF(path string) {
53	b, err := ioutil.ReadFile(path)
54	if err != nil {
55		log.Fatalln(err)
56	}
57	cr, lf := bytes.Count(b, []byte{13}), bytes.Count(b, []byte{10})
58	crlf := bytes.Count(b, []byte{13, 10})
59	if cr != crlf || lf != crlf {
60		if rel, err := filepath.Rel(runtime.GOROOT(), path); err == nil {
61			// Make the test failure more readable by showing a path relative to GOROOT.
62			path = rel
63		}
64		fmt.Printf("Windows batch file %s does not use strict CRLF line termination.\n", path)
65		fmt.Printf("Please convert it to CRLF before checking it in due to golang.org/issue/37791.\n")
66		os.Exit(1)
67	}
68}
69