func GeneratePatch(oldfileURL string, newfileURL string) (p *Patch, err error) {
	generatePatchMu.Lock()
	defer generatePatchMu.Unlock()
	p = new(Patch)
	if p.oldfile, err = downloadAsset(oldfileURL); err != nil {
		return nil, err
	}
	if p.newfile, err = downloadAsset(newfileURL); err != nil {
		return nil, err
	}
	if p.File, err = bsdiff(p.oldfile, p.newfile); err != nil {
		return nil, err
	}
	return p, nil
}
GeneratePatch compares the contents of two URLs and generates a patch.
package server
import (
	"crypto/sha256"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
)
var (
	generatePatchMu sync.Mutex
)
type Patch struct {
	oldfile string
	newfile string
	File    string
}
const (
	patchesDirectory = "patches/"
)
func init() {
	err := os.MkdirAll(patchesDirectory, os.ModeDir|0700)
	if err != nil {
		log.Fatalf("Could not create directory for storing patches: %q", err)
	}
}
func fileExists(s string) bool {
	if _, err := os.Stat(s); err == nil {
		return true
	}
	return false
}
func fileHash(s string) string {
	var err error
	var fp *os.File
	h := sha256.New()
	if fp, err = os.Open(s); err != nil {
		log.Fatalf("Failed to open file %s: %q", s, err)
	}
	defer fp.Close()
	if _, err = io.Copy(h, fp); err != nil {
		log.Fatalf("Failed to read file %s: %q", s, err)
	}
	return fmt.Sprintf("%x", h.Sum(nil))
}
func bspatch(oldfile string, newfile string, patchfile string) (err error) {
	if !fileExists(oldfile) {
		return fmt.Errorf("File %s does not exist.", oldfile)
	}
	if !fileExists(patchfile) {
		return fmt.Errorf("File %s does not exist.", oldfile)
	}
	cmd := exec.Command(
		"bspatch",
		oldfile,
		newfile,
		patchfile,
	)
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("Failed to apply patch with bspatch: %q", err)
	}
	return nil
}
func bsdiff(oldfile string, newfile string) (patchfile string, err error) {
	if !fileExists(oldfile) {
		return "", fmt.Errorf("File %s does not exist.", oldfile)
	}
	if !fileExists(newfile) {
		return "", fmt.Errorf("File %s does not exist.", oldfile)
	}
	oldfileHash := fileHash(oldfile)
	newfileHash := fileHash(newfile)
	patchfile = patchesDirectory + fmt.Sprintf("%x", sha256.Sum256([]byte(oldfileHash+"|"+newfileHash)))
	if fileExists(patchfile) {
		return patchfile, nil
	}
	cmd := exec.Command(
		"bsdiff",
		oldfile,
		newfile,
		patchfile,
	)
	if err := cmd.Run(); err != nil {
		return "", fmt.Errorf("Failed to generate patch with bsdiff: %q", err)
	}
	return patchfile, nil
}