forked from jmckaskill/go-capnproto
-
Notifications
You must be signed in to change notification settings - Fork 21
/
util_test.go
155 lines (124 loc) · 4.22 KB
/
util_test.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package capn_test
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"strings"
capn "github.com/glycerine/go-capnproto"
)
// some generally useful capnp/segment utilities
// shell out to display capnp bytes as human-readable text. Data flow:
// in-memory capn segment -> stdin to capnp decode -> stdout human-readble string form
func CapnpDecodeSegment(seg *capn.Segment, capnpExePath string, capnpSchemaFilePath string, typeName string) string {
// set defaults
if capnpExePath == "" {
capnpExePath = CheckAndGetCapnpPath()
}
if capnpSchemaFilePath == "" {
capnpSchemaFilePath = "aircraftlib/aircraft.capnp"
}
if typeName == "" {
typeName = "Z"
}
cs := []string{"decode", "--short", capnpSchemaFilePath, typeName}
cmd := exec.Command(capnpExePath, cs...)
cmdline := capnpExePath + " " + strings.Join(cs, " ")
buf := new(bytes.Buffer)
seg.WriteTo(buf)
cmd.Stdin = buf
var errout bytes.Buffer
cmd.Stderr = &errout
bs, err := cmd.Output()
if err != nil {
if err.Error() == "exit status 1" {
cwd, _ := os.Getwd()
fmt.Fprintf(os.Stderr, "\nCall to capnp in CapnpDecodeSegment(): '%s' in dir '%s' failed with status 1\n", cmdline, cwd)
fmt.Printf("stderr: '%s'\n", string(errout.Bytes()))
fmt.Printf("stdout: '%s'\n", string(bs))
}
panic(err)
}
return strings.TrimSpace(string(bs))
}
// reduce boilerplate, dump this segment to disk.
func SegToFile(seg *capn.Segment, filePath string) {
file, err := os.Create(filePath)
if err != nil {
panic(err)
}
seg.WriteTo(file)
file.Close()
}
// disk file of a capn segment -> in-memory capn segment -> stdin to capnp decode -> stdout human-readble string form
func CapnFileToText(serializedCapnpFilePathToDisplay string, capnpSchemaFilePath string, capnpExePath string) (string, error) {
// a) read file into Segment
byteslice, err := ioutil.ReadFile(serializedCapnpFilePathToDisplay)
if err != nil {
return "", err
}
seg, nbytes, err := capn.ReadFromMemoryZeroCopy(byteslice)
if err == io.EOF {
return "", err
}
if err != nil {
return "", err
}
if nbytes == 0 {
return "", errors.New(fmt.Sprintf("did not expect 0 bytes back from capn.ReadFromMemoryZeroCopy() on reading file '%s'", serializedCapnpFilePathToDisplay))
}
// b) tell CapnpDecodeSegment() to show the human-readable-text form of the message
// warning: CapnpDecodeSegment() may panic on you. It is a testing utility so that
// is desirable. For production, do something else.
return CapnpDecodeSegment(seg, capnpExePath, capnpSchemaFilePath, "Z"), nil
}
// return path to capnp if 'which' can find it. Feel free to replace this with
// a more general configuration mechanism.
func CheckAndGetCapnpPath() string {
path, err := exec.LookPath("capnp")
if err != nil {
panic(fmt.Sprintf("could not locate the capnp executable: put the capnp executable in your path: %s", err))
}
cmd := exec.Command(path, "id")
bs, err := cmd.Output()
if err != nil || string(bs[:3]) != `@0x` {
panic(fmt.Sprintf("%s id did not function: put a working capnp executable in your path. Err: %s", path, err))
}
return path
}
// take an already (packed or unpacked, depending on the packed flag) buffer of a serialized segment, and display it
func CapnpDecodeBuf(buf []byte, capnpExePath string, capnpSchemaFilePath string, typeName string, packed bool) string {
// set defaults
if capnpExePath == "" {
capnpExePath = CheckAndGetCapnpPath()
}
if capnpSchemaFilePath == "" {
capnpSchemaFilePath = "aircraftlib/aircraft.capnp"
}
if typeName == "" {
typeName = "Z"
}
cs := []string{"decode", "--short", capnpSchemaFilePath, typeName}
if packed {
cs = []string{"decode", "--short", "--packed", capnpSchemaFilePath, typeName}
}
cmd := exec.Command(capnpExePath, cs...)
cmdline := capnpExePath + " " + strings.Join(cs, " ")
cmd.Stdin = bytes.NewReader(buf)
var errout bytes.Buffer
cmd.Stderr = &errout
bs, err := cmd.Output()
if err != nil {
if err.Error() == "exit status 1" {
cwd, _ := os.Getwd()
fmt.Fprintf(os.Stderr, "\nCall to capnp in CapnpDecodeBuf(): '%s' in dir '%s' failed with status 1\n", cmdline, cwd)
fmt.Printf("stderr: '%s'\n", string(errout.Bytes()))
fmt.Printf("stdout: '%s'\n", string(bs))
}
panic(err)
}
return strings.TrimSpace(string(bs))
}