/
rewrite_version.go
122 lines (106 loc) · 2.53 KB
/
rewrite_version.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package main
import (
"bytes"
"encoding/binary"
"fmt"
"hash/crc32"
"io"
"os"
"strconv"
"strings"
)
func Rewrite(path string, version string) error {
m, err := info(path)
if err != nil {
fmt.Fprintln(os.Stderr, "cannot get information of the model:", err)
return err
}
bh := m.Header.BinaryHeader
bh.Major, bh.Minor, bh.Maintenance, err = parseVersion(version)
if err != nil {
fmt.Fprintln(os.Stderr, "invalid Jubatus version:", err)
return err
}
bh.CRC32, err = calcNewCRC32(path, &bh)
if err != nil {
fmt.Fprintln(os.Stderr, "cannot compute CRC32 of the new model:", err)
return err
}
f, err := os.OpenFile(path, os.O_WRONLY, 0644)
if err != nil {
fmt.Fprintln(os.Stderr, "cannot write to the file:", err)
return err
}
defer f.Close()
if err := binary.Write(f, binary.BigEndian, &bh); err != nil {
fmt.Fprintln(os.Stderr, "cannot write a new header to the file:", err)
return err
}
return nil
}
func parseVersion(version string) (major uint32, minor uint32, maintenance uint32, err error) {
vs := strings.Split(version, ".")
if len(vs) != 3 {
err = fmt.Errorf("the version doesn't contain three numbers")
return
}
vns := make([]uint32, 3)
for i, v := range vs {
n, e := strconv.ParseUint(v, 10, 32)
if e != nil {
err = e
return
}
vns[i] = uint32(n)
}
major, minor, maintenance = vns[0], vns[1], vns[2]
return
}
func calcNewCRC32(path string, newHeader *BinaryHeader) (uint32, error) {
buf := &bytes.Buffer{}
err := binary.Write(buf, binary.BigEndian, newHeader)
if err != nil {
return 0, err
}
header := buf.Bytes()
crc := crc32.Checksum(header[:28], crc32.IEEETable) // before crc32
crc = crc32.Update(crc, crc32.IEEETable, header[32:])
f, err := os.Open(path)
if err != nil {
return 0, err
}
defer f.Close()
if _, err := f.Seek(int64(len(header)), os.SEEK_SET); err != nil {
return 0, err
}
data := make([]byte, 4*1024*1024)
for {
n, err := f.Read(data)
crc = crc32.Update(crc, crc32.IEEETable, data[:n])
if err != nil {
if err != io.EOF {
return 0, err
}
break
}
}
return crc, nil
}
func ExecRewriteVersion(args []string) {
if len(args) != 2 {
RewriteVersionUsage()
}
err := Rewrite(args[0], args[1])
if err != nil {
os.Exit(1)
}
}
func RewriteVersionUsage() {
fmt.Println("Usage: jubamodel rewrite-version file new-version")
fmt.Println()
fmt.Println("Rewrite a Jubatus version of the given model file")
fmt.Println()
fmt.Println("Example:")
fmt.Println(" $ jubamodel rewrite-version /path/to/classifier.model 0.5.8")
os.Exit(1)
}