fork of go-gitdiff with jj support
at v0.4.0 2.5 kB view raw
1//+build ignore 2 3// bin.go is a helper CLI to manipulate binary diff data for testing purposes. 4// It can decode patches generated by git using the standard parsing functions 5// or it can encode binary data back into the format expected by Git. It 6// operates on stdin writes results (possibly binary) to stdout. 7 8package main 9 10import ( 11 "bytes" 12 "compress/zlib" 13 "encoding/binary" 14 "flag" 15 "io/ioutil" 16 "log" 17 "os" 18 "strings" 19 20 "github.com/bluekeyes/go-gitdiff/gitdiff" 21) 22 23var ( 24 b85Powers = []uint32{52200625, 614125, 7225, 85, 1} 25 b85Alpha = []byte( 26 "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "!#$%&()*+-;<=>?@^_`{|}~", 27 ) 28) 29 30var mode string 31 32func base85Encode(data []byte) []byte { 33 chunks, remaining := len(data)/4, len(data)%4 34 if remaining > 0 { 35 data = append(data, make([]byte, 4-remaining)...) 36 chunks++ 37 } 38 39 var n int 40 out := make([]byte, 5*chunks) 41 42 for i := 0; i < len(data); i += 4 { 43 v := binary.BigEndian.Uint32(data[i : i+4]) 44 for j := 0; j < 5; j++ { 45 p := v / b85Powers[j] 46 out[n+j] = b85Alpha[p] 47 v -= b85Powers[j] * p 48 } 49 n += 5 50 } 51 52 return out 53} 54 55func compress(data []byte) ([]byte, error) { 56 var b bytes.Buffer 57 w := zlib.NewWriter(&b) 58 59 if _, err := w.Write(data); err != nil { 60 return nil, err 61 } 62 if err := w.Close(); err != nil { 63 return nil, err 64 } 65 66 return b.Bytes(), nil 67} 68 69func wrap(data []byte) string { 70 var s strings.Builder 71 for i := 0; i < len(data); i += 52 { 72 c := 52 73 if c > len(data)-i { 74 c = len(data) - i 75 } 76 b := (c / 5) * 4 77 78 if b <= 26 { 79 s.WriteByte(byte('A' + b - 1)) 80 } else { 81 s.WriteByte(byte('a' + b - 27)) 82 } 83 s.Write(data[i : i+c]) 84 s.WriteByte('\n') 85 } 86 return s.String() 87} 88 89func init() { 90 flag.StringVar(&mode, "mode", "parse", "operation mode, one of 'parse' or 'encode'") 91} 92 93func main() { 94 flag.Parse() 95 96 switch mode { 97 case "parse": 98 files, _, err := gitdiff.Parse(os.Stdin) 99 if err != nil { 100 log.Fatalf("failed to parse file: %v", err) 101 } 102 if len(files) != 1 { 103 log.Fatalf("patch contains more than one file: %d", len(files)) 104 } 105 if files[0].BinaryFragment == nil { 106 log.Fatalf("patch file does not contain a binary fragment") 107 } 108 os.Stdout.Write(files[0].BinaryFragment.Data) 109 110 case "encode": 111 data, err := ioutil.ReadAll(os.Stdin) 112 if err != nil { 113 log.Fatalf("failed to read input: %v", err) 114 } 115 data, err = compress(data) 116 if err != nil { 117 log.Fatalf("failed to compress data: %v", err) 118 } 119 os.Stdout.WriteString(wrap(base85Encode(data))) 120 121 default: 122 log.Fatalf("unknown mode: %s", mode) 123 } 124}