Source file src/cmd/internal/diff/diff.go

     1  // Copyright 2019 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  // Package diff implements a Diff function that compare two inputs
     6  // using the 'diff' tool.
     7  package diff
     8  
     9  import (
    10  	"bytes"
    11  	exec "internal/execabs"
    12  	"io/ioutil"
    13  	"os"
    14  	"runtime"
    15  )
    16  
    17  // Returns diff of two arrays of bytes in diff tool format.
    18  func Diff(prefix string, b1, b2 []byte) ([]byte, error) {
    19  	f1, err := writeTempFile(prefix, b1)
    20  	if err != nil {
    21  		return nil, err
    22  	}
    23  	defer os.Remove(f1)
    24  
    25  	f2, err := writeTempFile(prefix, b2)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	defer os.Remove(f2)
    30  
    31  	cmd := "diff"
    32  	if runtime.GOOS == "plan9" {
    33  		cmd = "/bin/ape/diff"
    34  	}
    35  
    36  	data, err := exec.Command(cmd, "-u", f1, f2).CombinedOutput()
    37  	if len(data) > 0 {
    38  		// diff exits with a non-zero status when the files don't match.
    39  		// Ignore that failure as long as we get output.
    40  		err = nil
    41  	}
    42  
    43  	// If we are on Windows and the diff is Cygwin diff,
    44  	// machines can get into a state where every Cygwin
    45  	// command works fine but prints a useless message like:
    46  	//
    47  	//	Cygwin WARNING:
    48  	//	  Couldn't compute FAST_CWD pointer.  This typically occurs if you're using
    49  	//	  an older Cygwin version on a newer Windows.  Please update to the latest
    50  	//	  available Cygwin version from https://cygwin.com/.  If the problem persists,
    51  	//	  please see https://cygwin.com/problems.html
    52  	//
    53  	// Skip over that message and just return the actual diff.
    54  	if len(data) > 0 && !bytes.HasPrefix(data, []byte("--- ")) {
    55  		i := bytes.Index(data, []byte("\n--- "))
    56  		if i >= 0 && i < 80*10 && bytes.Contains(data[:i], []byte("://cygwin.com/")) {
    57  			data = data[i+1:]
    58  		}
    59  	}
    60  
    61  	return data, err
    62  }
    63  
    64  func writeTempFile(prefix string, data []byte) (string, error) {
    65  	file, err := ioutil.TempFile("", prefix)
    66  	if err != nil {
    67  		return "", err
    68  	}
    69  	_, err = file.Write(data)
    70  	if err1 := file.Close(); err == nil {
    71  		err = err1
    72  	}
    73  	if err != nil {
    74  		os.Remove(file.Name())
    75  		return "", err
    76  	}
    77  	return file.Name(), nil
    78  }
    79  

View as plain text