Commit ee7fdc26 authored by haya14busa's avatar haya14busa Committed by Brad Fitzpatrick

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 <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 89465027
......@@ -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"
......
......@@ -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)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment