github.com/jgbaldwinbrown/perf@v0.1.1/internal/diff/diff.go (about)

     1  // Copyright 2017 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
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"os/exec"
    11  	"runtime"
    12  )
    13  
    14  func writeTempFile(dir, prefix string, data []byte) (string, error) {
    15  	file, err := os.CreateTemp(dir, prefix)
    16  	if err != nil {
    17  		return "", err
    18  	}
    19  	_, err = file.Write(data)
    20  	if err1 := file.Close(); err == nil {
    21  		err = err1
    22  	}
    23  	if err != nil {
    24  		os.Remove(file.Name())
    25  		return "", err
    26  	}
    27  	return file.Name(), nil
    28  }
    29  
    30  // Diff returns a human-readable description of the differences between s1 and s2.
    31  // If the "diff" command is available, it returns the output of unified diff on s1 and s2.
    32  // If the result is non-empty, the strings differ or the diff command failed.
    33  func Diff(s1, s2 string) string {
    34  	if s1 == s2 {
    35  		return ""
    36  	}
    37  	if _, err := exec.LookPath("diff"); err != nil {
    38  		return fmt.Sprintf("diff command unavailable\nold: %q\nnew: %q", s1, s2)
    39  	}
    40  	f1, err := writeTempFile("", "benchfmt_test", []byte(s1))
    41  	if err != nil {
    42  		return err.Error()
    43  	}
    44  	defer os.Remove(f1)
    45  
    46  	f2, err := writeTempFile("", "benchfmt_test", []byte(s2))
    47  	if err != nil {
    48  		return err.Error()
    49  	}
    50  	defer os.Remove(f2)
    51  
    52  	cmd := "diff"
    53  	if runtime.GOOS == "plan9" {
    54  		cmd = "/bin/ape/diff"
    55  	}
    56  
    57  	data, err := exec.Command(cmd, "-u", f1, f2).CombinedOutput()
    58  	if len(data) > 0 {
    59  		// diff exits with a non-zero status when the files don't match.
    60  		// Ignore that failure as long as we get output.
    61  		err = nil
    62  	}
    63  	if err != nil {
    64  		data = append(data, []byte(err.Error())...)
    65  	}
    66  	return string(data)
    67  }