github.com/vugu/vugu@v0.3.5/vugufmt/diff.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // This file is a modification of https://golang.org/src/cmd/gofmt/gofmt.go
     6  
     7  package vugufmt
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"runtime"
    17  )
    18  
    19  func writeTempFile(dir, prefix string, data []byte) (string, error) {
    20  	file, err := ioutil.TempFile(dir, prefix)
    21  	if err != nil {
    22  		return "", err
    23  	}
    24  	_, err = file.Write(data)
    25  	if err1 := file.Close(); err == nil {
    26  		err = err1
    27  	}
    28  	if err != nil {
    29  		os.Remove(file.Name())
    30  		return "", err
    31  	}
    32  	return file.Name(), nil
    33  }
    34  
    35  func diff(b1, b2 []byte, filename string) (data []byte, err error) {
    36  	f1, err := writeTempFile("", "vugufmt", b1)
    37  	if err != nil {
    38  		return
    39  	}
    40  	defer os.Remove(f1)
    41  	f2, err := writeTempFile("", "vugufmt", b2)
    42  	if err != nil {
    43  		return
    44  	}
    45  	defer os.Remove(f2)
    46  	cmd := "diff"
    47  	if runtime.GOOS == "plan9" {
    48  		cmd = "/bin/ape/diff"
    49  	}
    50  	data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput()
    51  	if len(data) > 0 {
    52  		// diff exits with a non-zero status when the files don't match.
    53  		// Ignore that failure as long as we get output.
    54  		return replaceTempFilename(data, filename)
    55  	}
    56  	return
    57  }
    58  
    59  // replaceTempFilename replaces temporary filenames in diff with actual one.
    60  func replaceTempFilename(diff []byte, filename string) ([]byte, error) {
    61  
    62  	bs := bytes.SplitN(diff, []byte{'\n'}, 3)
    63  
    64  	if len(bs) < 3 {
    65  		return nil, fmt.Errorf("got unexpected diff for %s", filename)
    66  	}
    67  
    68  	// Preserve timestamps.
    69  	var t0, t1 []byte
    70  
    71  	if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 {
    72  		t0 = bs[0][i:]
    73  	}
    74  
    75  	if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 {
    76  		t1 = bs[1][i:]
    77  	}
    78  
    79  	// Always print filepath with slash separator.
    80  	f := filepath.ToSlash(filename)
    81  	bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0))
    82  	bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1))
    83  	return bytes.Join(bs, []byte{'\n'}), nil
    84  }