From: haya14busa Date: Sat, 4 Feb 2017 13:22:14 +0000 (+0900) Subject: cmd/gofmt: use actual filename in gofmt -d output X-Git-Tag: go1.9beta1~1675 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ee7fdc26477a0eaf5382542a7822b45966a9f844;p=gostls13.git cmd/gofmt: use actual filename in gofmt -d output By using actual filename, diff output of "gofmt -d" can be used with other commands like "diffstat" and "patch". Example: $ gofmt -d path/to/file.go | diffstat $ gofmt -d path/to/file.go > gofmt.patch $ patch -u -p0 < gofmt.patch Fixes #18932 Change-Id: I21ce15eb77870d72f2c14bfd5e7c21e2c77dc9ab Reviewed-on: https://go-review.googlesource.com/36374 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index e1ef0ddb83..cf1ddea917 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -139,11 +139,11 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error } } if *doDiff { - data, err := diff(src, res) + data, err := diff(src, res, filename) if err != nil { return fmt.Errorf("computing diff: %s", err) } - fmt.Printf("diff %s gofmt/%s\n", filename, filename) + fmt.Printf("diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename)) out.Write(data) } } @@ -225,7 +225,7 @@ func gofmtMain() { } } -func diff(b1, b2 []byte) (data []byte, err error) { +func diff(b1, b2 []byte, filename string) (data []byte, err error) { f1, err := ioutil.TempFile("", "gofmt") if err != nil { return @@ -248,9 +248,39 @@ func diff(b1, b2 []byte) (data []byte, err error) { // diff exits with a non-zero status when the files don't match. // Ignore that failure as long as we get output. err = nil + + data, err = replaceTempFilename(data, filename) } return +} +// replaceTempFilename replaces temporary filenames in diff with actual one. +// +// --- /tmp/gofmt316145376 2017-02-03 19:13:00.280468375 -0500 +// +++ /tmp/gofmt617882815 2017-02-03 19:13:00.280468375 -0500 +// ... +// -> +// --- path/to/file.go.orig 2017-02-03 19:13:00.280468375 -0500 +// +++ path/to/file.go 2017-02-03 19:13:00.280468375 -0500 +// ... +func replaceTempFilename(diff []byte, filename string) ([]byte, error) { + bs := bytes.SplitN(diff, []byte{'\n'}, 3) + if len(bs) < 3 { + return nil, fmt.Errorf("got unexpected diff for %s", filename) + } + // Preserve timestamps. + var t0, t1 []byte + if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 { + t0 = bs[0][i:] + } + if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 { + t1 = bs[1][i:] + } + // Always print filepath with slash separator. + f := filepath.ToSlash(filename) + bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0)) + bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1)) + return bytes.Join(bs, []byte{'\n'}), nil } const chmodSupported = runtime.GOOS != "windows" diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go index b7ca9e8d11..76fb250f4d 100644 --- a/src/cmd/gofmt/gofmt_test.go +++ b/src/cmd/gofmt/gofmt_test.go @@ -9,7 +9,9 @@ import ( "flag" "io/ioutil" "os" + "os/exec" "path/filepath" + "runtime" "strings" "testing" "text/scanner" @@ -110,7 +112,7 @@ func runTest(t *testing.T, in, out string) { } t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in) - d, err := diff(expected, got) + d, err := diff(expected, got, in) if err == nil { t.Errorf("%s", d) } @@ -184,3 +186,64 @@ func TestBackupFile(t *testing.T) { } t.Logf("Created: %s", name) } + +func TestDiff(t *testing.T) { + if _, err := exec.LookPath("diff"); err != nil { + t.Skipf("skip test on %s: diff command is required", runtime.GOOS) + } + in := []byte("first\nsecond\n") + out := []byte("first\nthird\n") + filename := "difftest.txt" + b, err := diff(in, out, filename) + if err != nil { + t.Fatal(err) + } + bs := bytes.SplitN(b, []byte{'\n'}, 3) + line0, line1 := bs[0], bs[1] + + if prefix := "--- difftest.txt.orig"; !bytes.HasPrefix(line0, []byte(prefix)) { + t.Errorf("diff: first line should start with `%s`\ngot: %s", prefix, line0) + } + + if prefix := "+++ difftest.txt"; !bytes.HasPrefix(line1, []byte(prefix)) { + t.Errorf("diff: second line should start with `%s`\ngot: %s", prefix, line1) + } + + want := `@@ -1,2 +1,2 @@ + first +-second ++third +` + + if got := string(bs[2]); got != want { + t.Errorf("diff: got:\n%s\nwant:\n%s", got, want) + } +} + +func TestReplaceTempFilename(t *testing.T) { + diff := []byte(`--- /tmp/tmpfile1 2017-02-08 00:53:26.175105619 +0900 ++++ /tmp/tmpfile2 2017-02-08 00:53:38.415151275 +0900 +@@ -1,2 +1,2 @@ + first +-second ++third +`) + want := []byte(`--- path/to/file.go.orig 2017-02-08 00:53:26.175105619 +0900 ++++ path/to/file.go 2017-02-08 00:53:38.415151275 +0900 +@@ -1,2 +1,2 @@ + first +-second ++third +`) + // Check path in diff output is always slash regardless of the + // os.PathSeparator (`/` or `\`). + sep := string(os.PathSeparator) + filename := strings.Join([]string{"path", "to", "file.go"}, sep) + got, err := replaceTempFilename(diff, filename) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(got, want) { + t.Errorf("os.PathSeparator='%s': replacedDiff:\ngot:\n%s\nwant:\n%s", sep, got, want) + } +}