]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/gofmt: use actual filename in gofmt -d output
authorhaya14busa <hayabusa1419@gmail.com>
Sat, 4 Feb 2017 13:22:14 +0000 (22:22 +0900)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 8 Feb 2017 19:04:35 +0000 (19:04 +0000)
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: Brad Fitzpatrick <bradfitz@golang.org>
src/cmd/gofmt/gofmt.go
src/cmd/gofmt/gofmt_test.go

index e1ef0ddb83717ae0210f4f8d1899afbd9d5587af..cf1ddea917cfd5d94f672742c960148ad1b31b14 100644 (file)
@@ -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"
index b7ca9e8d119082875c93bd36f108466104346185..76fb250f4dda80416c494aecef10b81a1686b828 100644 (file)
@@ -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)
+       }
+}