-
Notifications
You must be signed in to change notification settings - Fork 6
/
marshal.go
131 lines (110 loc) · 2.86 KB
/
marshal.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
// SPDX-License-Identifier: GPL-3.0
package proto
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"strings"
"github.com/bufbuild/protoyaml-go"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"gopkg.in/yaml.v2"
)
type Format struct {
unmarshal func(b []byte, m protoreflect.ProtoMessage) error
marshal func(m protoreflect.ProtoMessage) ([]byte, error)
}
func (f Format) Unmarshal(b []byte, m protoreflect.ProtoMessage) error {
return f.unmarshal(b, m)
}
func (f Format) Marshal(m protoreflect.ProtoMessage) ([]byte, error) {
return f.marshal(m)
}
func MarshalYaml(message proto.Message) ([]byte, error) { // Copied from protoyaml to use yaml.v2 (due to https://github.com/go-yaml/yaml/issues/720)
data, err := protojson.Marshal(message)
if err != nil {
return nil, err
}
var jsonVal interface{}
if err := json.Unmarshal(data, &jsonVal); err != nil {
return nil, err
}
return yaml.Marshal(jsonVal)
}
var Formats = map[string]Format{
"json": {protojson.Unmarshal, protojson.Marshal},
"yaml": {protoyaml.Unmarshal, MarshalYaml},
"yml": {protoyaml.Unmarshal, MarshalYaml},
"pb": {proto.Unmarshal, proto.Marshal},
"pbtext": {prototext.Unmarshal, prototext.Marshal},
}
var FormatNames []string
func init() {
FormatNames := make([]string, 0, len(Formats))
for name := range Formats {
FormatNames = append(FormatNames, name)
}
}
func Unmarshal(format string, bytes []byte, m protoreflect.ProtoMessage) error {
f, ok := Formats[format]
if !ok {
return errors.New("Unknown format: " + format)
}
err := f.Unmarshal(bytes, m)
if err != nil {
return fmt.Errorf("Failed unmarshalling as %s: %w", format, err)
}
return nil
}
func Marshal(format string, m protoreflect.ProtoMessage) ([]byte, error) {
f, ok := Formats[format]
if !ok {
return nil, errors.New("Unknown format: " + format)
}
bytes, err := f.Marshal(m)
if err != nil {
return nil, fmt.Errorf("Failed unmarshalling as %s: %w", format, err)
}
return bytes, nil
}
func DetectFormat(path string) string {
for name := range Formats {
if strings.HasSuffix(path, "."+name) {
return name
}
}
return path
}
func UnmarshalFile(path string, format string, m protoreflect.ProtoMessage) error {
file, err := os.Open(path)
if err != nil {
return err
}
bytes, err := io.ReadAll(file)
if err != nil {
return err
}
if format == "" {
format = DetectFormat(path)
}
return Unmarshal(format, bytes, m)
}
func MarshalFile(path string, format string, m protoreflect.ProtoMessage) error {
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
if format == "" {
format = DetectFormat(path)
}
bytes, err := Marshal(format, m)
if err != nil {
return err
}
_, err = file.Write(bytes)
return err
}