fork of go-gitdiff with jj support
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}