github.com/vugu/vugu@v0.3.6-0.20240430171613-3f6f402e014b/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  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"runtime"
    16  )
    17  
    18  func writeTempFile(dir, prefix string, data []byte) (string, error) {
    19  	file, err := os.CreateTemp(dir, prefix)
    20  	if err != nil {
    21  		return "", err
    22  	}
    23  	_, err = file.Write(data)
    24  	if err1 := file.Close(); err == nil {
    25  		err = err1
    26  	}
    27  	if err != nil {
    28  		os.Remove(file.Name())
    29  		return "", err
    30  	}
    31  	return file.Name(), nil
    32  }
    33  
    34  func diff(b1, b2 []byte, filename string) (data []byte, err error) {
    35  	f1, err := writeTempFile("", "vugufmt", b1)
    36  	if err != nil {
    37  		return
    38  	}
    39  	defer os.Remove(f1)
    40  	f2, err := writeTempFile("", "vugufmt", b2)
    41  	if err != nil {
    42  		return
    43  	}
    44  	defer os.Remove(f2)
    45  	cmd := "diff"
    46  	if runtime.GOOS == "plan9" {
    47  		cmd = "/bin/ape/diff"
    48  	}
    49  	data, err = exec.Command(cmd, "-u", f1, f2).CombinedOutput()
    50  	if len(data) > 0 {
    51  		// diff exits with a non-zero status when the files don't match.
    52  		// Ignore that failure as long as we get output.
    53  		return replaceTempFilename(data, filename)
    54  	}
    55  	return
    56  }
    57  
    58  // replaceTempFilename replaces temporary filenames in diff with actual one.
    59  func replaceTempFilename(diff []byte, filename string) ([]byte, error) {
    60  
    61  	bs := bytes.SplitN(diff, []byte{'\n'}, 3)
    62  
    63  	if len(bs) < 3 {
    64  		return nil, fmt.Errorf("got unexpected diff for %s", filename)
    65  	}
    66  
    67  	// Preserve timestamps.
    68  	var t0, t1 []byte
    69  
    70  	if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 {
    71  		t0 = bs[0][i:]
    72  	}
    73  
    74  	if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 {
    75  		t1 = bs[1][i:]
    76  	}
    77  
    78  	// Always print filepath with slash separator.
    79  	f := filepath.ToSlash(filename)
    80  	bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0))
    81  	bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1))
    82  	return bytes.Join(bs, []byte{'\n'}), nil
    83  }