}
}
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)
}
}
}
}
-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
// 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"
"flag"
"io/ioutil"
"os"
+ "os/exec"
"path/filepath"
+ "runtime"
"strings"
"testing"
"text/scanner"
}
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)
}
}
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)
+ }
+}