From 676794f73e6ca8fbd7ec14f4185625efda4e2ca8 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Wed, 15 Feb 2023 16:45:14 -0500 Subject: [PATCH] cmd/go: convert mkalldocs.sh to a Go program mkalldocs.sh required a Unix shell, making it less accessible for contributors on Windows. It also used a substantially different codepath to regenerate the file than the one used to check the file for staleness, making failures in TestDocsUpToDate more complex to diagnose. We can solve both of those problems by using the same technique as in checkScriptReadme: use the test itself as the generator to update the file. The test is already written in Go, the test binary already knows how to mimic the 'go' command, and this approach brings the difference between the test and the generator down to a single flag check. Updates #26735. Change-Id: I7c6f65cb0e0c29e334e38a45412e0a73c4d31d42 Reviewed-on: https://go-review.googlesource.com/c/go/+/468636 Reviewed-by: Alan Donovan TryBot-Result: Gopher Robot Run-TryBot: Bryan Mills Auto-Submit: Bryan Mills --- src/cmd/go/alldocs.go | 2 +- src/cmd/go/help_test.go | 59 ++++++++++++++++++++++---------- src/cmd/go/internal/help/help.go | 2 +- src/cmd/go/main.go | 2 +- src/cmd/go/mkalldocs.sh | 13 ------- 5 files changed, 43 insertions(+), 35 deletions(-) delete mode 100755 src/cmd/go/mkalldocs.sh diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 0f8433efca..fe17709016 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Code generated by mkalldocs.sh; DO NOT EDIT. +// Code generated by 'go test cmd/go -v -run=TestDocsUpToDate -fixdocs'; DO NOT EDIT. // Edit the documentation in other files and rerun mkalldocs.sh to generate this one. // Go is a tool for managing Go source code. diff --git a/src/cmd/go/help_test.go b/src/cmd/go/help_test.go index 3e1d817ca5..7f05cdf2cb 100644 --- a/src/cmd/go/help_test.go +++ b/src/cmd/go/help_test.go @@ -5,37 +5,58 @@ package main_test import ( - "bytes" + "flag" "go/format" - diffpkg "internal/diff" + "internal/diff" + "internal/testenv" "os" + "strings" "testing" - - "cmd/go/internal/help" - "cmd/go/internal/modload" ) +var fixDocs = flag.Bool("fixdocs", false, "if true, update alldocs.go") + func TestDocsUpToDate(t *testing.T) { - t.Parallel() + if !*fixDocs { + t.Parallel() + } - if !modload.Enabled() { - t.Skipf("help.Help in GOPATH mode is configured by main.main") + // We run 'go help documentation' as a subprocess instead of + // calling help.Help directly because it may be sensitive to + // init-time configuration + cmd := testenv.Command(t, testGo, "help", "documentation") + // Unset GO111MODULE so that the 'go get' section matches + // the default 'go get' implementation. + cmd.Env = append(cmd.Environ(), "GO111MODULE=") + cmd.Stderr = new(strings.Builder) + out, err := cmd.Output() + if err != nil { + t.Fatalf("%v: %v\n%s", cmd, err, cmd.Stderr) } - buf := new(bytes.Buffer) - // Match the command in mkalldocs.sh that generates alldocs.go. - help.Help(buf, []string{"documentation"}) - internal := buf.Bytes() - internal, err := format.Source(internal) + alldocs, err := format.Source(out) if err != nil { - t.Fatalf("gofmt docs: %v", err) + t.Fatalf("format.Source($(%v)): %v", cmd, err) } - alldocs, err := os.ReadFile("alldocs.go") + + const srcPath = `alldocs.go` + old, err := os.ReadFile(srcPath) if err != nil { - t.Fatalf("error reading alldocs.go: %v", err) + t.Fatalf("error reading %s: %v", srcPath, err) + } + diff := diff.Diff(srcPath, old, "go help documentation | gofmt", alldocs) + if diff == nil { + t.Logf("%s is up to date.", srcPath) + return } - if !bytes.Equal(internal, alldocs) { - t.Errorf("alldocs.go is not up to date; run mkalldocs.sh to regenerate it\n%s", - diffpkg.Diff("go help documentation | gofmt", internal, "alldocs.go", alldocs)) + + if *fixDocs { + if err := os.WriteFile(srcPath, alldocs, 0666); err != nil { + t.Fatal(err) + } + t.Logf("wrote %d bytes to %s", len(alldocs), srcPath) + } else { + t.Logf("\n%s", diff) + t.Errorf("%s is stale. To update, run 'go generate cmd/go'.", srcPath) } } diff --git a/src/cmd/go/internal/help/help.go b/src/cmd/go/internal/help/help.go index 804c910dac..dd1f2f745c 100644 --- a/src/cmd/go/internal/help/help.go +++ b/src/cmd/go/internal/help/help.go @@ -27,7 +27,7 @@ func Help(w io.Writer, args []string) { fmt.Fprintln(w, "// Use of this source code is governed by a BSD-style") fmt.Fprintln(w, "// license that can be found in the LICENSE file.") fmt.Fprintln(w) - fmt.Fprintln(w, "// Code generated by mkalldocs.sh; DO NOT EDIT.") + fmt.Fprintln(w, "// Code generated by 'go test cmd/go -v -run=TestDocsUpToDate -fixdocs'; DO NOT EDIT.") fmt.Fprintln(w, "// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.") fmt.Fprintln(w) buf := new(strings.Builder) diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index ee705e87e0..8d1c3c0e8b 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:generate ./mkalldocs.sh +//go:generate go test cmd/go -v -run=TestDocsUpToDate -fixdocs package main diff --git a/src/cmd/go/mkalldocs.sh b/src/cmd/go/mkalldocs.sh deleted file mode 100755 index a2b0aca3c9..0000000000 --- a/src/cmd/go/mkalldocs.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2012 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. - -set -e - -go build -o go.latest -# If the command used to generate alldocs.go changes, update TestDocsUpToDate in -# help_test.go. -GO111MODULE='' ./go.latest help documentation >alldocs.go -gofmt -w alldocs.go -rm go.latest -- 2.50.0